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 |
||||
|
||||
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