Browse Source

open

master
pioneer 2 years ago
commit
4da830d8d6
  1. 6
      README.md
  2. BIN
      lib/finekit-10.0-20220427.jar
  3. 24
      plugin.xml
  4. 113
      src/main/java/com/fr/plugin/DESUtil.java
  5. 12
      src/main/java/com/fr/plugin/FunctionRecoder.java
  6. 49
      src/main/java/com/fr/plugin/LDYConfig.java
  7. 18
      src/main/java/com/fr/plugin/LDYLifeCycleMonitor.java
  8. 235
      src/main/java/com/fr/plugin/filter/LDY1Filter.java
  9. 17
      src/main/java/com/fr/plugin/http/LDYHttpHandler.java
  10. 16
      src/main/java/com/fr/plugin/http/LDYUrlAliasProvider.java
  11. 46
      src/main/java/com/fr/plugin/http/handler/ALLGetTicket1Handler.java
  12. 45
      src/main/java/com/fr/plugin/http/handler/ALLLogout1Handler.java

6
README.md

@ -0,0 +1,6 @@
# open-JSD-10349
JSD-10349 单点集成\
免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\
仅作为开发者学习参考使用!禁止用于任何商业用途!\
为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系【pioneer】处理。

BIN
lib/finekit-10.0-20220427.jar

Binary file not shown.

24
plugin.xml

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<plugin>
<id>com.eco.plugin.xx.ldy</id>
<name><![CDATA[六朵云德SSO]]></name>
<active>yes</active>
<version>1.2.3</version>
<env-version>10.0</env-version>
<jartime>2021-02-10</jartime>
<vendor>fr.open</vendor>
<main-package>com.fr.plugin</main-package>
<!--用来记录这个任务的创建时间-->
<description><![CDATA[
]]></description>
<!--任务ID: 10349-->
<create-day>2022-5-26 18:05:54</create-day>
<extra-decision>
<HttpHandlerProvider class="com.fr.plugin.http.LDYHttpHandler"/>
<URLAliasProvider class="com.fr.plugin.http.LDYUrlAliasProvider"/>
<GlobalRequestFilterProvider class="com.fr.plugin.filter.LDY1Filter"/>
</extra-decision>
<lifecycle-monitor class="com.fr.plugin.LDYLifeCycleMonitor"/>
<function-recorder class="com.fr.plugin.FunctionRecoder"/>
</plugin>

113
src/main/java/com/fr/plugin/DESUtil.java

@ -0,0 +1,113 @@
package com.fr.plugin;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.security.Security;
/**
* 注意DES加密和解密过程中密钥长度都必须是8的倍数
*/
public class DESUtil {
//设置java支持PKCS7Padding
static {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
/**
* DES加密 加密填充模式DES/ECB/PKCS7Padding
* @param datasource byte[] 要加密的byte数组
* @param password String 私钥8的倍数
* @return byte[]
*/
public static byte[] encrypt(byte[] datasource, String password) {
try {
SecureRandom random = new SecureRandom();
DESKeySpec desKey = new DESKeySpec(password.getBytes());
// 创建一个密匙工厂,然后用它把DESKeySpec转换成
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(desKey);
// Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance("DES");
// 用密匙初始化Cipher对象
cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
// 现在,获取数据并加密
// 正式执行加密操作
return cipher.doFinal(addZero(datasource));
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
/**
* DES加密 加密填充模式DES/ECB/PKCS7Padding
* @param src byte[] 要解密的数组
* @param password String 私钥8的倍数
* @return byte[]
* @throws Exception
*/
public static byte[] decrypt(byte[] src, String password) throws Exception {
// DES算法要求有一个可信任的随机数源
SecureRandom random = new SecureRandom();
// 创建一个DESKeySpec对象
DESKeySpec desKey = new DESKeySpec((password.getBytes()));
// 创建一个密匙工厂
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
// 将DESKeySpec对象转换成SecretKey对象
SecretKey securekey = keyFactory.generateSecret(desKey);
// Cipher对象实际完成解密操作
Cipher cipher = Cipher.getInstance("DES");
// 用密匙初始化Cipher对象
cipher.init(Cipher.DECRYPT_MODE, securekey, random);
// 真正开始解密操作
return cipher.doFinal(src);
}
public static byte[] getKey(byte[] keyRule) {
SecretKeySpec key = null;
byte[] keyByte = keyRule;
System.out.println(keyByte.length);
// 创建一个空的八位数组,默认情况下为0
byte[] byteTemp = new byte[8];
// 将用户指定的规则转换成八位数组
int i = 0;
for (; i < byteTemp.length && i < keyByte.length; i++) {
byteTemp[i] = keyByte[i];
}
key = new SecretKeySpec(byteTemp, "DES");
return key.getEncoded();
}
public static byte[] addZero(byte[] data) {
byte[] dataByte = data;
if (data.length % 8 != 0) {
byte[] temp = new byte[8 - data.length % 8];
dataByte = byteMerger(data, temp);
}
return dataByte;
}
// java 合并两个byte数组
// System.arraycopy()方法
public static byte[] byteMerger(byte[] bt1, byte[] bt2) {
byte[] bt3 = new byte[bt1.length + bt2.length];
System.arraycopy(bt1, 0, bt3, 0, bt1.length);
System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);
return bt3;
}
/**
* byte数组转hex
* @param bytes
* @return
*/
public static String byteToHex(byte[] bytes){
String strHex = "";
StringBuilder sb = new StringBuilder("");
for (int n = 0; n < bytes.length; n++) {
strHex = Integer.toHexString(bytes[n] & 0xFF);
sb.append((strHex.length() == 1) ? "0" + strHex : strHex); // 每个字节由两个字符表示,位数不够,高位补0
}
return sb.toString().trim();
}
}

12
src/main/java/com/fr/plugin/FunctionRecoder.java

@ -0,0 +1,12 @@
package com.fr.plugin;
import com.fr.plugin.transform.ExecuteFunctionRecord;
import com.fr.plugin.transform.FunctionRecorder;
@FunctionRecorder
public class FunctionRecoder {
@ExecuteFunctionRecord
public void exe(){
System.out.println("插件功能埋点,虽然不会执行,除非上架应用");
}
}

49
src/main/java/com/fr/plugin/LDYConfig.java

@ -0,0 +1,49 @@
package com.fr.plugin;
import com.fr.config.*;
import com.fr.config.holder.Conf;
import com.fr.config.holder.factory.Holders;
@Visualization(category = "xxSSO配置")
public class LDYConfig extends DefaultConfiguration {
private static volatile LDYConfig config = null;
public static LDYConfig getInstance() {
if (config == null) {
config = ConfigContext.getConfigInstance(LDYConfig.class);
}
return config;
}
@Identifier(value = "apiUrl", name = "接口地址", description = "描述", status = Status.SHOW)
private Conf<String> apiUrl = Holders.simple("");
@Identifier(value = "oaDesKey", name = "OA单点DES秘钥", description = "OA单点DES秘钥", status = Status.SHOW)
private Conf<String> oaDesKey = Holders.simple("");
public String getOaDesKey() {
return oaDesKey.get();
}
public void setOaDesKey(String oaDesKey) {
this.oaDesKey.set(oaDesKey);
}
public String getApiUrl() {
return apiUrl.get();
}
public void setApiUrl(String apiUrl) {
this.apiUrl.set(apiUrl);
}
@Override
public Object clone() throws CloneNotSupportedException {
LDYConfig cloned = (LDYConfig) super.clone();
cloned.apiUrl = (Conf<String>) this.apiUrl.clone();
cloned.oaDesKey = (Conf<String>) this.oaDesKey.clone();
return cloned;
}
}

18
src/main/java/com/fr/plugin/LDYLifeCycleMonitor.java

@ -0,0 +1,18 @@
package com.fr.plugin;
import com.fr.plugin.context.PluginContext;
import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor;
import com.fr.stable.fun.Authorize;
@Authorize
public class LDYLifeCycleMonitor extends AbstractPluginLifecycleMonitor {
@Override
public void afterRun(PluginContext pluginContext) {
LDYConfig.getInstance();
}
@Override
public void beforeStop(PluginContext pluginContext) {
}
}

235
src/main/java/com/fr/plugin/filter/LDY1Filter.java

@ -0,0 +1,235 @@
package com.fr.plugin.filter;
import com.fanruan.api.log.LogKit;
import com.fanruan.api.net.http.HttpKit;
import com.fr.base.ServerConfig;
import com.fr.data.NetworkHelper;
import com.fr.decision.authority.data.User;
import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider;
import com.fr.decision.mobile.terminal.TerminalHandler;
import com.fr.decision.webservice.v10.login.LoginService;
import com.fr.decision.webservice.v10.login.TokenResource;
import com.fr.decision.webservice.v10.user.UserService;
import com.fr.json.JSONObject;
import com.fr.log.FineLoggerFactory;
import com.fr.plugin.DESUtil;
import com.fr.plugin.LDYConfig;
import com.fr.stable.StringUtils;
import com.fr.stable.web.Device;
import com.fr.web.utils.WebUtils;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
public class LDY1Filter extends AbstractGlobalRequestFilterProvider {
@Override
public String filterName() {
return "LDY1Filter";
}
@Override
public String[] urlPatterns() {
return new String[]{
"/*",
};
}
@Override
public void init(FilterConfig filterConfig) {
super.init(filterConfig);
}
public static String decode(String s,String pwd) {
try {
byte[] basebak= java.util.Base64.getDecoder().decode(s);
byte[] result=DESUtil.decrypt(basebak,pwd);
return new String(result).trim();
} catch (Exception e) {
LogKit.error("解密失败",e);
return "";
}
}
@Override
public void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) {
try {
if (needFilter(req) && !isLogin(req)) {
//oa 的登录
String loginid = req.getParameter("workcode");
UserService userService = UserService.getInstance();
if(StringUtils.isNotBlank(loginid)){
LogKit.info("收到OA单点:{}",loginid);
LDYConfig ldyConfig = LDYConfig.getInstance();
String oaDesKey = ldyConfig.getOaDesKey();
String decodeJSON = decode(loginid, oaDesKey);
JSONObject entries = new JSONObject(decodeJSON);
String userName = entries.getString("workcode");
User user = userService.getUserByUserName(userName);
if (user == null) {
WebUtils.printAsString(res, userName+"用户不存在---OA登录");
return;
}
login(req, res, userName);
sendRedirect(res,getUrl(req));
return;
}
String ticket = req.getParameter("ticket");
String token = req.getParameter("token");
if (StringUtils.isBlank(ticket)||StringUtils.isBlank(token)) {
WebUtils.printAsString(res, "ticket or token is null");
return;
}
String userId = checkTicket(ticket, token);
if (StringUtils.isBlank(userId)) {
WebUtils.printAsString(res, "检查用户ID失败,请检查来源");
return;
}
User user = userService.getUserByUserName(userId);
if (user == null) {
WebUtils.printAsString(res, userId + "用户不存在");
return;
}
login(req, res, userId);
sendRedirect(res,getUrl(req));
return;
}
filterChain.doFilter(req, res);
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
private String getUrl(HttpServletRequest request) {
StringBuilder builder = new StringBuilder();
String url = "/";
try {
url = request.getScheme() + "://" + request.getServerName()//服务器地址
+ ":"
+ request.getServerPort() + request.getRequestURI();
builder.append(url);
Enumeration<String> parameterNames = request.getParameterNames();
builder.append("?q=1");
while (parameterNames.hasMoreElements()) {
String key = parameterNames.nextElement();
if (StringUtils.equals(key, "workcode")) {
continue;
}
if (StringUtils.equals(key, "ticket")) {
continue;
}
builder.append("&").append(key).append("=").append(request.getParameter(key));
}
} catch (Exception e) {
e.printStackTrace();
}
return builder.toString();
}
private String checkTicket(String ticket, String token) throws IOException {
LDYConfig config = LDYConfig.getInstance();
String base = config.getApiUrl();
String url = base + "/open/api/exhibition/ticket/validate?ticket=" + ticket;
Map<String, String> header = new HashMap<>();
header.put("Authorization", "Bearer " + token);
String res = HttpKit.get(url, new HashMap<>(), header);
LogKit.info("url:{} token :{} checkTicket res:{}" ,url,token,res);
JSONObject entries = new JSONObject(res);
if (StringUtils.equals(entries.getString("success"), "true")) {
return entries.getString("data");
}
return "";
}
private boolean needFilter(HttpServletRequest request) {
String requestURI = request.getRequestURI();
if (StringUtils.isNotBlank(requestURI) && request.getMethod().equals("GET") ) {
if (requestURI.endsWith("decision")||requestURI.endsWith("decision/") ) {
return true;
}
if (requestURI.endsWith("/url/patch/web/page")) {
return true;
}
if (requestURI.endsWith("/view/form") || requestURI.endsWith("/view/report")) {
if (StringUtils.isNotBlank(request.getParameter("viewlet"))) {
return true;
}
}
if (requestURI.contains("/v10/entry/access/") && request.getMethod().equals("GET")) {
return true;
}
if (requestURI.contains("/v5/design/report") && (requestURI.endsWith("/edit") || requestURI.endsWith("/view"))) {
return true;
}
}
return false;
}
private void sendRedirect(HttpServletResponse res, String url) {
res.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
res.setHeader("Location", url);
}
private void delLoginOut(HttpServletRequest req, HttpServletResponse res) {
try {
//执行帆软内部的退出
LoginService.getInstance().logout(req, res);
JSONObject jsonObject = new JSONObject();
jsonObject.put("data", "login");
//调用外部接口注销accessToken
WebUtils.printAsJSON(res, jsonObject);
} catch (Exception e) {
}
}
private boolean isLogOut(HttpServletRequest req) {
String url = WebUtils.getOriginalURL(req);
String servletNamePrefix = "/" + ServerConfig.getInstance().getServletName() + "/logout";
return url.contains(servletNamePrefix) && req.getMethod().equals("POST");
}
private void login(HttpServletRequest req, HttpServletResponse res, String username) {
String token = null;
try {
token = LoginService.getInstance().login(req, res, username);
req.setAttribute("fine_auth_token", token);
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
FineLoggerFactory.getLogger().error("login failed");
}
FineLoggerFactory.getLogger().error("login success");
}
private boolean isLogin(HttpServletRequest request) {
String oldToken = TokenResource.COOKIE.getToken(request);
return oldToken != null && checkTokenValid(request, (String) oldToken);
}
private boolean checkTokenValid(HttpServletRequest req, String token) {
try {
Device device = NetworkHelper.getDevice(req);
LoginService.getInstance().loginStatusValid(token, TerminalHandler.getTerminal(req, device));
return true;
} catch (Exception ignore) {
}
return false;
}
private static void setCookie(HttpServletResponse response, String name, String value) {
Cookie cookie = new Cookie(name, value);
cookie.setPath("/");
response.addCookie(cookie);
}
}

17
src/main/java/com/fr/plugin/http/LDYHttpHandler.java

@ -0,0 +1,17 @@
package com.fr.plugin.http;
import com.fr.decision.fun.HttpHandler;
import com.fr.decision.fun.impl.AbstractHttpHandlerProvider;
import com.fr.plugin.http.handler.*;
public class LDYHttpHandler extends AbstractHttpHandlerProvider {
HttpHandler[] actions = new HttpHandler[]{
new ALLGetTicket1Handler(),
new ALLLogout1Handler()
};
@Override
public HttpHandler[] registerHandlers() {
return actions;
}
}

16
src/main/java/com/fr/plugin/http/LDYUrlAliasProvider.java

@ -0,0 +1,16 @@
package com.fr.plugin.http;
import com.fr.decision.fun.impl.AbstractURLAliasProvider;
import com.fr.decision.webservice.url.alias.URLAlias;
import com.fr.decision.webservice.url.alias.URLAliasFactory;
public class LDYUrlAliasProvider extends AbstractURLAliasProvider {
@Override
public URLAlias[] registerAlias() {
return new URLAlias[]{
URLAliasFactory.createPluginAlias("/getTicket", "/getTicket", true),
URLAliasFactory.createPluginAlias("/logout", "/logout", true),
};
}
}

46
src/main/java/com/fr/plugin/http/handler/ALLGetTicket1Handler.java

@ -0,0 +1,46 @@
package com.fr.plugin.http.handler;
import com.fanruan.api.log.LogKit;
import com.fanruan.api.net.http.HttpKit;
import com.fr.decision.fun.impl.BaseHttpHandler;
import com.fr.json.JSONObject;
import com.fr.plugin.LDYConfig;
import com.fr.third.springframework.web.bind.annotation.RequestMethod;
import com.fr.web.utils.WebUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
public class ALLGetTicket1Handler extends BaseHttpHandler {
@Override
public RequestMethod getMethod() {
return null;
}
@Override
public String getPath() {
return "/getTicket";
}
@Override
public boolean isPublic() {
return true;
}
@Override
public void handle(HttpServletRequest req, HttpServletResponse res) throws Exception {
String token = WebUtils.getHTTPRequestParameter(req, "token");
String url = WebUtils.getHTTPRequestParameter(req, "url");
LDYConfig config = LDYConfig.getInstance();
String base = config.getApiUrl();
String getUrl = base + "/open/api/exhibition/ticket?loginUrl="+url;
Map<String, String> params = new HashMap<>();
Map<String, String> header = new HashMap<>();
header.put("Authorization", "Bearer "+token);
String json = HttpKit.get(getUrl, params, header);
LogKit.info("loginUrl:{} token:{} ALLGetTicket1Handler json:{}",getUrl,header,json);
WebUtils.printAsJSON(res, new JSONObject(json));
}
}

45
src/main/java/com/fr/plugin/http/handler/ALLLogout1Handler.java

@ -0,0 +1,45 @@
package com.fr.plugin.http.handler;
import com.fanruan.api.log.LogKit;
import com.fanruan.api.net.http.HttpKit;
import com.fr.decision.fun.impl.BaseHttpHandler;
import com.fr.json.JSONObject;
import com.fr.plugin.LDYConfig;
import com.fr.third.springframework.web.bind.annotation.RequestMethod;
import com.fr.web.utils.WebUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
public class ALLLogout1Handler extends BaseHttpHandler {
@Override
public RequestMethod getMethod() {
return null;
}
@Override
public String getPath() {
return "/logout";
}
@Override
public boolean isPublic() {
return true;
}
@Override
public void handle(HttpServletRequest req, HttpServletResponse res) throws Exception {
String token = WebUtils.getHTTPRequestParameter(req, "token");
LDYConfig config = LDYConfig.getInstance();
String base = config.getApiUrl();
String getUrl = base + "/open/api/exhibition/logout";
Map<String, String> params = new HashMap<>();
Map<String, String> header = new HashMap<>();
header.put("Authorization", "Bearer "+token);
String json = HttpKit.get(getUrl, params, header);
LogKit.info("loginUrl:{} token:{} ALLGetTicket1Handler json:{}",getUrl,header,json);
WebUtils.printAsJSON(res, new JSONObject(json));
}
}
Loading…
Cancel
Save