Browse Source

提交开源材料

10.0
LAPTOP-SB56SG4Q\86185 3 years ago
parent
commit
f1e388ce89
  1. BIN
      JSD-8380-需求确认书V1.docx
  2. 7
      README.md
  3. 5
      crc.properties
  4. 18
      plugin.xml
  5. 6
      readme.txt
  6. 132
      src/main/java/com/fr/plugin/crc/sso/CommonUtils.java
  7. 11
      src/main/java/com/fr/plugin/crc/sso/PluginConstants.java
  8. 173
      src/main/java/com/fr/plugin/crc/sso/RIGFilter.java
  9. 143
      src/main/java/com/fr/plugin/crc/sso/SsoFilter.java
  10. 34
      src/main/resources/com/fr/plugin/crc-sso.html
  11. 24
      src/main/resources/com/fr/plugin/index.js
  12. 15
      src/main/resources/com/fr/plugin/write-cookie.html
  13. 5
      src/main/resources/crc.properties

BIN
JSD-8380-需求确认书V1.docx

Binary file not shown.

7
README.md

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

5
crc.properties

@ -0,0 +1,5 @@
env=uat
devUser=1
isLocal=true
appId=xxxxxxxxxxxxxxxx
appSecret=xxxxxxxxxxxxxxxxxxx

18
plugin.xml

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<plugin>
<id>com.fr.plugin.crc.sso</id>
<name><![CDATA[单点登录]]></name>
<active>yes</active>
<version>1.17</version>
<env-version>10.0</env-version>
<jartime>2018-07-31</jartime>
<vendor>fr.open</vendor>
<description><![CDATA[单点登录]]></description>
<change-notes><![CDATA[]]></change-notes>
<extra-decision>
<GlobalRequestFilterProvider class="com.fr.plugin.crc.sso.SsoFilter"/>
<GlobalRequestFilterProvider class="com.fr.plugin.crc.sso.RIGFilter"/>
<!-- <LogInOutEventProvider class="com.fr.plugin.crc.sso.CustomLogInOutEventProvider"/>-->
</extra-decision>
<function-recorder class="com.fr.plugin.crc.sso.SsoFilter"/>
</plugin>

6
readme.txt

@ -0,0 +1,6 @@
此次完成功能如下
a、单点登录
1、将压缩文件解压后的crc.properties配置文件拷贝至 %部署路径%/WEB-INF/resources, 并修改相应的属性配置
2、安装本插件,插件安装见连接http://help.finereport.com/doc-view-2198.html
3、进入系统测试单点登录,访问地址为http://ip:port/webroot/decision/crc/sso

132
src/main/java/com/fr/plugin/crc/sso/CommonUtils.java

@ -0,0 +1,132 @@
package com.fr.plugin.crc.sso;
import com.fr.data.NetworkHelper;
import com.fr.decision.authority.data.User;
import com.fr.decision.mobile.terminal.TerminalHandler;
import com.fr.decision.webservice.utils.DecisionServiceConstants;
import com.fr.decision.webservice.utils.DecisionStatusService;
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.log.FineLoggerFactory;
import com.fr.stable.StringUtils;
import com.fr.stable.web.Device;
import com.fr.web.utils.WebUtils;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.Properties;
/**
* @author fr.open
* @since 2021/7/29
*/
public class CommonUtils {
public static String getProperty(Properties props, String key, String defaultValue, boolean allowBlank) {
String value = props.getProperty(key);
if (StringUtils.isNotBlank(value)) {
return value;
} else {
if (allowBlank) {
FineLoggerFactory.getLogger().warn("Property[" + key + "] value is blank.");
return defaultValue;
} else {
throw new IllegalArgumentException("Property[" + key + "] cann't be blank.");
}
}
}
public static String getProperty(Properties props, String key, boolean allowBlank) {
return getProperty(props, key, null, allowBlank);
}
public static String getProperty(Properties props, String key) {
return getProperty(props, key, null, true);
}
public static boolean isLogin(HttpServletRequest request) {
String oldToken = TokenResource.COOKIE.getToken(request);
return oldToken != null && checkTokenValid(request, (String) oldToken);
}
private static 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;
}
/**
* 跳转到过滤器链中的下一个过滤器
*
* @param request
* @param response
* @param chain
*/
public static void next(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
try {
chain.doFilter(request, response);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void login(String username, HttpServletRequest request, HttpServletResponse response) {
try {
User user = UserService.getInstance().getUserByUserName(username);
if (user == null) {
throw new RuntimeException("系统未授权, 当前用户是\"" + username + "\"");
}
String token = LoginService.getInstance().login(request, response, username);
request.setAttribute(DecisionServiceConstants.FINE_AUTH_TOKEN_NAME, token);
} catch (Exception e) {
FineLoggerFactory.getLogger().error("sso >> Failed to login with[" + username + "]", e);
throw new RuntimeException("用户\"" + username +"\"登录失败");
}
}
public static boolean isMobileDevice(HttpServletRequest request) {
if (WebUtils.getDevice(request).isMobile()) {
FineLoggerFactory.getLogger().info("current request is is mobile request ,url is {}", request.getRequestURI());
return true;
}
String requestHeader = request.getHeader("user-agent");
String[] deviceArray = new String[]{"android", "iphone", "ipad", "ios", "windows phone", "wechat"};
if (requestHeader == null) {
return false;
}
requestHeader = requestHeader.toLowerCase();
for (int i = 0; i < deviceArray.length; i++) {
if (requestHeader.toLowerCase().contains(deviceArray[i])) {
FineLoggerFactory.getLogger().info("current request:{} is mobile request!", request.getRequestURI());
return true;
}
}
String op = WebUtils.getHTTPRequestParameter(request, "op");
return StringUtils.isNotBlank(op) && StringUtils.equals("h5",op);
}
public static void cacheParams(String key, Map<String, String> values) {
try {
DecisionStatusService.originUrlStatusService().put(key, values);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String getCachedParam(String key, String name) {
try {
Map<String, String> values = DecisionStatusService.originUrlStatusService().get(key);
return values.get(name);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

11
src/main/java/com/fr/plugin/crc/sso/PluginConstants.java

@ -0,0 +1,11 @@
package com.fr.plugin.crc.sso;
/**
* @Author fr.open
* @Date 2021/9/24
* @Description
**/
public class PluginConstants {
public static final String PLUGIN_ID = "com.fr.plugin.crc.sso";
}

173
src/main/java/com/fr/plugin/crc/sso/RIGFilter.java

@ -0,0 +1,173 @@
package com.fr.plugin.crc.sso;
import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider;
import com.fr.decision.webservice.utils.WebServiceUtils;
import com.fr.general.PropertiesUtils;
import com.fr.general.http.HttpToolbox;
import com.fr.intelli.record.Focus;
import com.fr.intelli.record.Original;
import com.fr.json.JSONObject;
import com.fr.locale.InterProviderFactory;
import com.fr.log.FineLoggerFactory;
import com.fr.plugin.context.PluginContexts;
import com.fr.plugin.transform.FunctionRecorder;
import com.fr.stable.StringUtils;
import com.fr.stable.fun.Authorize;
import com.fr.third.org.apache.commons.codec.binary.Base64;
import com.fr.web.utils.WebUtils;
import javax.servlet.FilterChain;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Stream;
import static com.fr.plugin.crc.sso.CommonUtils.*;
/**
* @author fr.open
* @since 2021/9/2
*/
@FunctionRecorder
@Authorize(callSignKey = PluginConstants.PLUGIN_ID)
public class RIGFilter extends AbstractGlobalRequestFilterProvider {
private final static String[] NOT_FILTER = {
"/decision/file",
"/decision/resources",
"/system",
"/materials.min.js.map",
"/remote",
"/login",
"/url/mobile",
"/crc/sso",
"/login/config"
};
private String apiLogin;
private String apiGetToken;
private String clientId;
private String clientSecret;
private String redirectURI;
private void initParams() {
Properties props = PropertiesUtils.getProperties("crc");
apiLogin = getProperty(props, "rig.api.login", false);
apiGetToken = getProperty(props, "rig.api.get-token", false);
clientId = getProperty(props, "rig.api.client_id", false);
clientSecret = getProperty(props, "rig.api.client_secret", false);
redirectURI = getProperty(props, "rig.api.redirect_uri", false);
}
@Override
public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
if (isAccept(request)) {
next(request, response, chain);
return;
}
try {
initParams();
String ticket = request.getParameter("ticket");
if (StringUtils.isBlank(ticket)) {
jumpAuthorize(request, response);
return;
}
String[] splitted = ticket.split("\\.");
String code = splitted[splitted.length - 1];
login(getUsername(getToken(code, response)), request, response);
next(request, response, chain);
} catch (Exception e) {
FineLoggerFactory.getLogger().error("RIG sso >>> 处理单点登陆时发生错误", e);
setError(response, e.getMessage());
}
}
private String getUsername(String token) {
try {
FineLoggerFactory.getLogger().info("RIG sso >>> 获取到的token值为 ==> \"{}\"", token);
String res = new String(Base64.decodeBase64(token.split("\\.")[1]));
FineLoggerFactory.getLogger().info("RIG sso >>> Base64 decode 后的token值为 ==> \"{}\"", res);
JSONObject body = new JSONObject(res);
if (body.has("user_name")) {
return body.getString("user_name");
}
throw new RuntimeException("解析token获取用户名失败");
} catch (Exception e) {
throw new RuntimeException("获取token失败, " + e.getMessage());
}
}
private String getToken(String code, HttpServletResponse response) throws IOException {
String api = String.format("%s?grant_type=authorization_code&client_id=%s&client_secret=%s&code=%s", apiGetToken, clientId, clientSecret, code);
FineLoggerFactory.getLogger().info("RIG sso >>> 获取 token 请求地址 ==> \"{}\"", api);
String res = HttpToolbox.post(api, Collections.emptyMap());
JSONObject body = new JSONObject(res);
if (body.has("refresh_token")) {
Cookie c = new Cookie("RIG_REFRESH_TOKEN", body.getString("refresh_token"));
c.setPath("/");
response.addCookie(c);
}
if (body.has("access_token")) {
Cookie c = new Cookie("RIG_ACCESS_TOKEN", body.getString("access_token"));
c.setPath("/");
response.addCookie(c);
return body.getString("access_token");
}
throw new RuntimeException("获取 token 接口请求失败, " + res);
}
private void jumpAuthorize(HttpServletRequest request, HttpServletResponse response) throws IOException {
String login = String.format("%s?service=%s", apiLogin, redirectURI);
FineLoggerFactory.getLogger().info("RIG sso >>> 跳转到登陆页面 ==> \"{}\"", login);
response.sendRedirect(login);
}
@Override
public String filterName() {
return "rigFilter";
}
@Override
@Focus(id = PluginConstants.PLUGIN_ID, text = "单点登录", source = Original.PLUGIN)
public String[] urlPatterns() {
if(!PluginContexts.currentContext().isAvailable()){
return new String[0];
}
return new String[]{"/*"};
}
public boolean isAccept(HttpServletRequest request) {
String url = request.getRequestURL().toString();
if (Stream.of(NOT_FILTER).anyMatch(url::contains)) {
return true;
}
return isLogin(request);
}
private void setError(HttpServletResponse res, String reason) {
try {
PrintWriter printWriter = WebUtils.createPrintWriter(res);
Map<String, Object> map = new HashMap<>();
map.put("result", InterProviderFactory.getProvider().getLocText("Fine-Engine_Error_Page_Result"));
map.put("reason", reason);
map.put("solution", InterProviderFactory.getProvider().getLocText("Fine-Engine_Please_Contact_Platform_Admin"));
String page = WebServiceUtils.parseWebPageResourceSafe("com/fr/web/controller/decision/entrance/resources/unavailable.html", map);
printWriter.write(page);
printWriter.flush();
printWriter.close();
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
}

143
src/main/java/com/fr/plugin/crc/sso/SsoFilter.java

@ -0,0 +1,143 @@
package com.fr.plugin.crc.sso;
import com.fr.base.TemplateUtils;
import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider;
import com.fr.decision.webservice.utils.WebServiceUtils;
import com.fr.general.PropertiesUtils;
import com.fr.intelli.record.Focus;
import com.fr.intelli.record.Original;
import com.fr.locale.InterProviderFactory;
import com.fr.log.FineLoggerFactory;
import com.fr.plugin.context.PluginContexts;
import com.fr.plugin.transform.FunctionRecorder;
import com.fr.stable.StringUtils;
import com.fr.stable.fun.Authorize;
import com.fr.web.utils.WebUtils;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Stream;
import static com.fr.plugin.crc.sso.CommonUtils.*;
/**
* @author fr.open
* @since 2021/7/29
*/
@FunctionRecorder
@Authorize(callSignKey = PluginConstants.PLUGIN_ID)
public class SsoFilter extends AbstractGlobalRequestFilterProvider {
private static String[] NOT_FILTER = {
"/decision/file",
"/decision/resources",
"/system",
"/materials.min.js.map",
"/remote",
"/login",
"/url/mobile",
"/login/config"
};
private final String env;
private final String devUser;
private final boolean isLocal;
private final String appId;
private final String appSecret;
public SsoFilter() {
Properties props = PropertiesUtils.getProperties("crc");
this.env = getProperty(props, "env", true);
this.devUser = getProperty(props, "devUser", true);
this.isLocal = Boolean.parseBoolean(getProperty(props, "isLocal", true));
this.appId = getProperty(props, "appId", true);
this.appSecret = getProperty(props, "appSecret", true);
}
@Override
public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
if (request.getRequestURI().endsWith("/crc/sso")) {
FineLoggerFactory.getLogger().info("sso >> 进入Filter, 当前URL为: \"{}\"", request.getRequestURI() + "?" + request.getQueryString());
try {
String root = TemplateUtils.render("${fineServletURL}");
if (isAccept(request)) {
FineLoggerFactory.getLogger().info("sso >> 已登录, 跳转到 ==> {}", root + "/url/mobile");
response.sendRedirect(root + "/url/mobile");
return;
}
String username = request.getParameter("username");
if (StringUtils.isBlank(username)) {
FineLoggerFactory.getLogger().info("sso >> 未获取到用户名, 跳转到 ==> crc-sso.html");
PrintWriter writer = WebUtils.createPrintWriter(response);
Map<String, Object> attributes = new HashMap<>();
attributes.put("root", root);
attributes.put("env", env);
attributes.put("devUser", devUser);
attributes.put("appId", appId);
attributes.put("appSecret", appSecret);
attributes.put("isLocal", isLocal);
String page = WebServiceUtils.parseWebPageResource("com/fr/plugin/crc-sso.html", attributes);
writer.write(page);
writer.flush();
writer.close();
} else {
FineLoggerFactory.getLogger().info("sso >> 获取到有用户名, 用户名为: \"{}\" 执行登录并跳转到 ==> {}", username, root + "/url/mobile");
login(username, request, response);
response.sendRedirect(root + "/url/mobile");
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error("单点登录处理失败.", e);
setError(response, e.getMessage());
}
} else {
next(request, response, chain);
}
}
@Override
public String filterName() {
return "sso";
}
@Override
@Focus(id = PluginConstants.PLUGIN_ID, text = "单点登录", source = Original.PLUGIN)
public String[] urlPatterns() {
if(!PluginContexts.currentContext().isAvailable()){
return new String[0];
}
return new String[]{"/decision/crc/sso"};
}
private boolean isAccept(HttpServletRequest request) {
return isLogin(request);
}
private void setError(HttpServletResponse res, String reason) {
try {
PrintWriter printWriter = WebUtils.createPrintWriter(res);
Map<String, Object> map = new HashMap<>();
map.put("result", InterProviderFactory.getProvider().getLocText("Fine-Engine_Error_Page_Result"));
map.put("reason", reason);
map.put("solution", InterProviderFactory.getProvider().getLocText("Fine-Engine_Please_Contact_Platform_Admin"));
String page = WebServiceUtils.parseWebPageResourceSafe("com/fr/web/controller/decision/entrance/resources/unavailable.html", map);
printWriter.write(page);
printWriter.flush();
printWriter.close();
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
}

34
src/main/resources/com/fr/plugin/crc-sso.html

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<title>单点登录</title>
<script type="text/javascript" src="https://s0.pstatp.com/ee/lark/js_sdk/h5-js-sdk-1.4.11.js"></script>
<script type="text/javascript" src="${root}/file?path=com/fr/plugin/index.js&type=plain&parser=plain"></script>
<script>
window.onload = function() {
document.writeln("页面加载完成......, 当前时间为 ==>" + new Date().getTime())
document.writeln("<br/>")
var runworkH5 = new window.runworkHelp.RunWorkH5({
env: "${env}",
isLocal: ${isLocal},
devUser: "${devUser}",
appId: "${appId}",
appSecret: "${appSecret}",
isHrInfo: true
});
document.writeln("runworkH5 js_sdk 初始化完成......<br/>")
runworkH5.initReady().then(() => {
document.writeln("runworkH5获取用户信息成功, 用户名为 ==> " + runworkH5.ldap);
document.writeln("<br/>")
document.writeln("当前时间为 ==>" + new Date().getTime());
document.writeln("<br/>")
location.href = "${root}/crc/sso?username=" + runworkH5.ldap;
})
}
</script>
</head>
<body></body>
</html>

24
src/main/resources/com/fr/plugin/index.js

File diff suppressed because one or more lines are too long

15
src/main/resources/com/fr/plugin/write-cookie.html

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<title>单点登录-回填cookie</title>
<script>
window.onload = function() {
const token = "${token}";
document.cookie = "fine_auth_token=" + token;
location.href = "${root}";
}
</script>
</head>
<body></body>
</html>

5
src/main/resources/crc.properties

@ -0,0 +1,5 @@
env=uat
devUser=1
isLocal=true
appId=xxxxxxxxxxxxxxxx
appSecret=xxxxxxxxxxxxxxxxxxx
Loading…
Cancel
Save