LAPTOP-SB56SG4Q\86185
3 years ago
10 changed files with 346 additions and 1 deletions
Binary file not shown.
@ -1,3 +1,5 @@ |
|||||||
# open-JSD-7639 |
# open-JSD-7639 |
||||||
|
|
||||||
JSD-7639、JSD-5860 开源任务代码 |
JSD-7639、JSD-5860 开源任务代码\ |
||||||
|
免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\ |
||||||
|
仅作为开发者学习参考使用!禁止用于任何商业用途! |
@ -0,0 +1,17 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||||
|
<plugin> |
||||||
|
<id>com.fr.plugin.jsd3998.sso</id> |
||||||
|
<name><![CDATA[移动端h5单点登录需求]]></name> |
||||||
|
<active>yes</active> |
||||||
|
<version>1.9</version> |
||||||
|
<env-version>10.0</env-version> |
||||||
|
<jartime>2018-07-31</jartime> |
||||||
|
<vendor>fr.open</vendor> |
||||||
|
<description><![CDATA[移动端h5单点登录需求]]></description> |
||||||
|
<change-notes><![CDATA[]]></change-notes> |
||||||
|
<extra-decision> |
||||||
|
<HttpHandlerProvider class="com.fr.plugin.jsd3998.sso.SsoRequestHandlerBridge"/> |
||||||
|
<URLAliasProvider class="com.fr.plugin.jsd3998.sso.SsoRequestURLAliasBridge" /> |
||||||
|
</extra-decision> |
||||||
|
<function-recorder class="com.fr.plugin.jsd3998.sso.SsoRequestHandlerBridge"/> |
||||||
|
</plugin> |
@ -0,0 +1,64 @@ |
|||||||
|
package com.fr.plugin.jsd3998.sso; |
||||||
|
|
||||||
|
import com.fr.third.org.apache.commons.codec.binary.Base64; |
||||||
|
|
||||||
|
import javax.crypto.Cipher; |
||||||
|
import javax.crypto.spec.SecretKeySpec; |
||||||
|
import java.security.Key; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Holger |
||||||
|
* @date 2019/1/18 |
||||||
|
*/ |
||||||
|
public class DesECBUtil { |
||||||
|
/** |
||||||
|
* 加密数据 |
||||||
|
* |
||||||
|
* @param encryptString |
||||||
|
* @param encryptKey |
||||||
|
* @return |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public static String encryptDES(String encryptString, String encryptKey) throws Exception { |
||||||
|
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); |
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(getKey(encryptKey), "DES")); |
||||||
|
byte[] encryptedData = cipher.doFinal(encryptString.getBytes("gb2312")); |
||||||
|
return Base64.encodeBase64String(encryptedData); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* key 不足8位补位 |
||||||
|
* |
||||||
|
* @param |
||||||
|
*/ |
||||||
|
public static byte[] getKey(String keyRule) { |
||||||
|
Key key = null; |
||||||
|
byte[] keyByte = keyRule.getBytes(); |
||||||
|
// 创建一个空的八位数组,默认情况下为0
|
||||||
|
byte[] byteTemp = new byte[8]; |
||||||
|
// 将用户指定的规则转换成八位数组
|
||||||
|
for (int i = 0; i < byteTemp.length && i < keyByte.length; i++) { |
||||||
|
byteTemp[i] = keyByte[i]; |
||||||
|
} |
||||||
|
key = new SecretKeySpec(byteTemp, "DES"); |
||||||
|
return key.getEncoded(); |
||||||
|
} |
||||||
|
|
||||||
|
/*** |
||||||
|
* 解密数据 |
||||||
|
* @param decryptString |
||||||
|
* @param decryptKey |
||||||
|
* @return |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
|
||||||
|
public static String decryptDES(String decryptString, String decryptKey) throws Exception { |
||||||
|
byte[] sourceBytes = Base64.decodeBase64(decryptString); |
||||||
|
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); |
||||||
|
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(getKey(decryptKey), "DES")); |
||||||
|
byte[] decoded = cipher.doFinal(sourceBytes); |
||||||
|
return new String(decoded, "UTF-8"); |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,113 @@ |
|||||||
|
package com.fr.plugin.jsd3998.sso; |
||||||
|
|
||||||
|
import com.fr.base.PropertiesUtils; |
||||||
|
import com.fr.decision.authority.data.User; |
||||||
|
import com.fr.decision.fun.impl.BaseHttpHandler; |
||||||
|
import com.fr.decision.webservice.exception.user.UserNotExistException; |
||||||
|
import com.fr.decision.webservice.utils.DecisionServiceConstants; |
||||||
|
import com.fr.decision.webservice.v10.login.LoginService; |
||||||
|
import com.fr.decision.webservice.v10.user.UserService; |
||||||
|
import com.fr.json.JSONObject; |
||||||
|
import com.fr.log.FineLoggerFactory; |
||||||
|
import com.fr.stable.StringUtils; |
||||||
|
import com.fr.third.org.apache.commons.lang3.math.NumberUtils; |
||||||
|
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.Calendar; |
||||||
|
import java.util.Properties; |
||||||
|
|
||||||
|
// @EnableMetrics
|
||||||
|
public class H5SsoHandler extends BaseHttpHandler { |
||||||
|
|
||||||
|
@Override |
||||||
|
public RequestMethod getMethod() { |
||||||
|
return RequestMethod.GET; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getPath() { |
||||||
|
return "/h5/callback"; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isPublic() { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void handle(HttpServletRequest request, HttpServletResponse response) throws Exception { |
||||||
|
Properties props = PropertiesUtils.getProperties("sso"); |
||||||
|
String encryptKey = props.getProperty("encrypt.key"); |
||||||
|
Long ticketTimeoutInSeconds = NumberUtils.createLong(props.getProperty("ticket.timeoutInSeconds", "300")); |
||||||
|
String ticket = request.getParameter("ticket"); |
||||||
|
FineLoggerFactory.getLogger().info("获取到的ticket值为[{}]", ticket); |
||||||
|
if (StringUtils.isNotBlank(ticket)) { |
||||||
|
ticket = DesECBUtil.decryptDES(ticket, encryptKey); |
||||||
|
FineLoggerFactory.getLogger().info("解密后的ticket值为[{}]", ticket); |
||||||
|
String[] tickets = ticket.split("\\+"); |
||||||
|
String username = tickets[0]; |
||||||
|
FineLoggerFactory.getLogger().info("获取到username为[{}]", username); |
||||||
|
Long ticketTime = NumberUtils.createLong(tickets[1]); |
||||||
|
Long nowTime = Calendar.getInstance().getTimeInMillis(); |
||||||
|
JSONObject res = new JSONObject(); |
||||||
|
if ((nowTime - ticketTime) > ticketTimeoutInSeconds * 1000) { |
||||||
|
FineLoggerFactory.getLogger().info("ticket[{}]已过期", ticket); |
||||||
|
request.getRequestDispatcher("/login.html").forward(request, response); |
||||||
|
res.put("res", "ticket已过期"); |
||||||
|
WebUtils.printAsJSON(response, res); |
||||||
|
return; |
||||||
|
} |
||||||
|
if (loginFromToken(request, response, username)) { |
||||||
|
request.getRequestDispatcher( "/decision/url/mobile").forward(request, response); |
||||||
|
} else { |
||||||
|
res.put("res", "fail"); |
||||||
|
WebUtils.printAsJSON(response, res); |
||||||
|
} |
||||||
|
} else { |
||||||
|
FineLoggerFactory.getLogger().info("未找到用户名,跳转到登录页面"); |
||||||
|
request.getRequestDispatcher("/login.html").forward(request, response); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected boolean loginFromToken(HttpServletRequest req, HttpServletResponse res, String username) throws Exception { |
||||||
|
try { |
||||||
|
if (com.fr.stable.StringUtils.isNotEmpty(username)) { |
||||||
|
FineLoggerFactory.getLogger().info("current username:" + username); |
||||||
|
User user = UserService.getInstance().getUserByUserName(username); |
||||||
|
FineLoggerFactory.getLogger().info("get user:" + user); |
||||||
|
if (user == null) { |
||||||
|
throw new UserNotExistException(); |
||||||
|
} |
||||||
|
String token = LoginService.getInstance().login(req, res, username); |
||||||
|
FineLoggerFactory.getLogger().info("get login token:" + token); |
||||||
|
req.setAttribute(DecisionServiceConstants.FINE_AUTH_TOKEN_NAME, token); |
||||||
|
FineLoggerFactory.getLogger().info("username:" + username + " login success"); |
||||||
|
return true; |
||||||
|
} else { |
||||||
|
FineLoggerFactory.getLogger().warn("username is null!"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
// public static void main(String... args) throws Exception {
|
||||||
|
// String ticket = URLDecoder.decode("7O%2Fyt%2FGeLqg8fxjY4Lm8%2F31FkSgLZh3a", "utf-8");
|
||||||
|
// System.out.println(ticket);
|
||||||
|
// ticket = DesECBUtil.decryptDES(ticket, "1111111111111111111");
|
||||||
|
// System.out.println(ticket);
|
||||||
|
// String[] tickets = ticket.split("\\+");
|
||||||
|
// String username = tickets[0];
|
||||||
|
// System.out.println(username);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// String t = "1+" + Calendar.getInstance().getTimeInMillis();
|
||||||
|
// System.out.println(URLEncoder.encode(DesECBUtil.encryptDES(t, "1111111111111111111"), "utf-8"));
|
||||||
|
// }
|
||||||
|
} |
@ -0,0 +1,95 @@ |
|||||||
|
package com.fr.plugin.jsd3998.sso; |
||||||
|
|
||||||
|
import com.fr.decision.authority.data.User; |
||||||
|
import com.fr.decision.fun.impl.BaseHttpHandler; |
||||||
|
import com.fr.decision.webservice.Response; |
||||||
|
import com.fr.decision.webservice.exception.user.UserNotExistException; |
||||||
|
import com.fr.decision.webservice.utils.DecisionServiceConstants; |
||||||
|
import com.fr.decision.webservice.v10.login.LoginService; |
||||||
|
import com.fr.decision.webservice.v10.user.UserService; |
||||||
|
import com.fr.json.JSONObject; |
||||||
|
import com.fr.log.FineLoggerFactory; |
||||||
|
import com.fr.record.analyzer.EnableMetrics; |
||||||
|
import com.fr.stable.StringUtils; |
||||||
|
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; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author luomiao |
||||||
|
* @since 2020/08/28 |
||||||
|
*/ |
||||||
|
@EnableMetrics |
||||||
|
public class SsoHttpHandler extends BaseHttpHandler { |
||||||
|
@Override |
||||||
|
public RequestMethod getMethod() { |
||||||
|
return RequestMethod.GET; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getPath() { |
||||||
|
return "/sso"; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isPublic() { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void handle(HttpServletRequest request, HttpServletResponse response) throws Exception { |
||||||
|
String src = request.getParameter("src"); |
||||||
|
String username = request.getParameter("username"); |
||||||
|
if ("sys".equals(src) && StringUtils.isNotBlank(username)) { |
||||||
|
JSONObject res = new JSONObject(); |
||||||
|
response.setContentType("application/json;charset=UTF-8"); |
||||||
|
if (loginFromToken(request, response, username)) { |
||||||
|
res.put("res", "success"); |
||||||
|
WebUtils.printAsJSON(response, res); |
||||||
|
} else { |
||||||
|
res.put("res", "fail"); |
||||||
|
WebUtils.printAsJSON(response, res); |
||||||
|
} |
||||||
|
} else if (!"sys".equals(src)) { |
||||||
|
FineLoggerFactory.getLogger().info("未找到用户名,跳转到登录页面"); |
||||||
|
request.getRequestDispatcher("/login.html").forward(request, response); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected boolean loginFromToken(HttpServletRequest req, HttpServletResponse res, String username) throws Exception { |
||||||
|
try { |
||||||
|
if (com.fr.stable.StringUtils.isNotEmpty(username)) { |
||||||
|
FineLoggerFactory.getLogger().info("current username:" + username); |
||||||
|
User user = UserService.getInstance().getUserByUserName(username); |
||||||
|
FineLoggerFactory.getLogger().info("get user:" + user); |
||||||
|
if (user == null) { |
||||||
|
throw new UserNotExistException(); |
||||||
|
} |
||||||
|
String token = LoginService.getInstance().login(req, res, username); |
||||||
|
FineLoggerFactory.getLogger().info("get login token:" + token); |
||||||
|
req.setAttribute(DecisionServiceConstants.FINE_AUTH_TOKEN_NAME, token); |
||||||
|
FineLoggerFactory.getLogger().info("username:" + username + " login success"); |
||||||
|
return true; |
||||||
|
} else { |
||||||
|
FineLoggerFactory.getLogger().warn("username is null!"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
protected void sendError(HttpServletResponse response, String errorCode) { |
||||||
|
Response res = Response.error(errorCode, errorCode); |
||||||
|
try { |
||||||
|
response.setContentType("application/json;charset=UTF-8"); |
||||||
|
WebUtils.printAsJSON(response, JSONObject.mapFrom(res)); |
||||||
|
} catch (Exception e) { |
||||||
|
FineLoggerFactory.getLogger().error("输出响应错误失败", e); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
package com.fr.plugin.jsd3998.sso; |
||||||
|
|
||||||
|
import com.fr.decision.fun.HttpHandler; |
||||||
|
import com.fr.decision.fun.impl.AbstractHttpHandlerProvider; |
||||||
|
import com.fr.plugin.transform.FunctionRecorder; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author luomiao |
||||||
|
* @since 2020/08/28 |
||||||
|
*/ |
||||||
|
@FunctionRecorder |
||||||
|
public class SsoRequestHandlerBridge extends AbstractHttpHandlerProvider { |
||||||
|
@Override |
||||||
|
public HttpHandler[] registerHandlers() { |
||||||
|
return new HttpHandler[]{ |
||||||
|
new SsoHttpHandler(), |
||||||
|
new H5SsoHandler() |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
package com.fr.plugin.jsd3998.sso; |
||||||
|
|
||||||
|
import com.fr.decision.fun.impl.AbstractURLAliasProvider; |
||||||
|
import com.fr.decision.webservice.url.alias.URLAlias; |
||||||
|
import com.fr.decision.webservice.url.alias.URLAliasFactory; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author luomiao |
||||||
|
* @since 2020/08/28 |
||||||
|
*/ |
||||||
|
public class SsoRequestURLAliasBridge extends AbstractURLAliasProvider { |
||||||
|
@Override |
||||||
|
public URLAlias[] registerAlias() { |
||||||
|
return new URLAlias[]{ |
||||||
|
URLAliasFactory.createPluginAlias("/sso", "/sso", true), |
||||||
|
URLAliasFactory.createPluginAlias("/h5/callback", "/h5/callback", true) |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,2 @@ |
|||||||
|
encrypt.key=1111111111111111111 |
||||||
|
ticket.timeoutInSeconds=300 |
@ -0,0 +1,13 @@ |
|||||||
|
|
||||||
|
此次完成功能如下 |
||||||
|
a、单点登录 |
||||||
|
|
||||||
|
1、安装本插件,插件安装见连接http://help.finereport.com/doc-view-2198.html |
||||||
|
|
||||||
|
2、将sso.properties件复制到 %tomcat_home%/webapps/webroot/WEB-INF/classes下, 并修改文件中的ticket加密密钥和时间戳超时时间 |
||||||
|
|
||||||
|
|
||||||
|
2、进入系统测试单点登录,访问地址为http://ip:port/webroot/decision/url/doH5Login,示例为本地地址http://localhost:8075/webroot/decision/url/h5/callback?ticket=XXXX 其中ticket的格式应为 用户名_时间戳 |
||||||
|
|
||||||
|
5、登录成功后会跳转到移动html5端首页。 |
||||||
|
如页面打印出“单点登录失败”可能原因是获取ticket失败或解析ticket中的用户名在系统中不存在 |
Loading…
Reference in new issue