Browse Source

open

master
pioneer 2 years ago
commit
28ec8e5995
  1. 6
      README.md
  2. BIN
      doc/JSD-9985-需求确认书V2.docx
  3. BIN
      doc/JSD-9985配置使用文档.docx
  4. BIN
      lib/cas/cas-client-core-3.2.1.jar
  5. BIN
      lib/cas/casclient.jar
  6. BIN
      lib/cas/commons-logging-1.1.jar
  7. BIN
      lib/finekit-10.0.jar
  8. 28
      plugin.xml
  9. 38
      src/main/java/com/fr/plugin/fbpa/LocaleFinder.java
  10. 34
      src/main/java/com/fr/plugin/fbpa/PluginMonitor.java
  11. 64
      src/main/java/com/fr/plugin/fbpa/config/FbpaConfig.java
  12. 133
      src/main/java/com/fr/plugin/fbpa/request/IgnoreFilter.java
  13. 174
      src/main/java/com/fr/plugin/fbpa/request/LoginFilter.java
  14. 94
      src/main/java/com/fr/plugin/fbpa/request/SSOFilter.java
  15. 9
      src/main/resources/com/fr/plugin/fbpa/locale/lang.properties
  16. 9
      src/main/resources/com/fr/plugin/fbpa/locale/lang_zh_CN.properties
  17. 97
      src/main/resources/com/fr/plugin/fbpa/web/unavailable.html

6
README.md

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

BIN
doc/JSD-9985-需求确认书V2.docx

Binary file not shown.

BIN
doc/JSD-9985配置使用文档.docx

Binary file not shown.

BIN
lib/cas/cas-client-core-3.2.1.jar

Binary file not shown.

BIN
lib/cas/casclient.jar

Binary file not shown.

BIN
lib/cas/commons-logging-1.1.jar

Binary file not shown.

BIN
lib/finekit-10.0.jar

Binary file not shown.

28
plugin.xml

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
<id>com.fr.plugin.fbpa.sso</id>
<name><![CDATA[单点登陆_EK]]></name>
<active>yes</active>
<version>1.0.2</version>
<env-version>11.0</env-version>
<jartime>2021-10-31</jartime>
<vendor>fr.open</vendor>
<description><![CDATA[单点登陆]]></description>
<change-notes><![CDATA[
[2022-06-22]JSD-9885插件初始化<br/>
]]></change-notes>
<main-package>com.fr.plugin.fbpa</main-package>
<prefer-packages>
<prefer-package>com.fanruan.api.*</prefer-package>
</prefer-packages>
<lifecycle-monitor class="com.fr.plugin.fbpa.PluginMonitor"/>
<extra-core>
<LocaleFinder class="com.fr.plugin.fbpa.LocaleFinder"/>
</extra-core>
<extra-decision>
<GlobalRequestFilterProvider class="com.fr.plugin.fbpa.request.IgnoreFilter"/>
<GlobalRequestFilterProvider class="com.fr.plugin.fbpa.request.SSOFilter"/>
<GlobalRequestFilterProvider class="com.fr.plugin.fbpa.request.LoginFilter"/>
</extra-decision>
<function-recorder class="com.fr.plugin.fbpa.LocaleFinder"/>
</plugin>

38
src/main/java/com/fr/plugin/fbpa/LocaleFinder.java

@ -0,0 +1,38 @@
/*
* Copyright (C), 2018-2020
* Project: starter
* FileName: LocaleFinder
* Author: xx
* Date: 2020/8/31 22:19
*/
package com.fr.plugin.fbpa;
import com.fr.intelli.record.Focus;
import com.fr.intelli.record.Original;
import com.fr.record.analyzer.EnableMetrics;
import com.fr.stable.fun.Authorize;
import com.fr.stable.fun.impl.AbstractLocaleFinder;
/**
* <Function Description><br>
* <LocaleFinder>
*
* @author xx
* @since 1.0.0
*/
@Authorize(callSignKey = LocaleFinder.PLUGIN_ID)
@EnableMetrics
public class LocaleFinder extends AbstractLocaleFinder {
public static final String PLUGIN_ID = "com.fr.plugin.fbpa.sso";
@Override
@Focus(id = PLUGIN_ID, text = "Plugin-fbpa", source = Original.PLUGIN)
public String find() {
return "com/fr/plugin/fbpa/locale/lang";
}
@Override
public int currentAPILevel() {
return CURRENT_LEVEL;
}
}

34
src/main/java/com/fr/plugin/fbpa/PluginMonitor.java

@ -0,0 +1,34 @@
/*
* Copyright (C), 2018-2021
* Project: starter
* FileName: PluginMonitor
* Author: xx
* Date: 2021/3/30 15:10
*/
package com.fr.plugin.fbpa;
import com.fr.plugin.context.PluginContext;
import com.fr.plugin.fbpa.config.FbpaConfig;
import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor;
/**
* <Function Description><br>
* <PluginMonitor>
*
* @author xx
* @since 1.0.0
*/
public class PluginMonitor extends AbstractPluginLifecycleMonitor {
public PluginMonitor() {
}
@Override
public void afterRun(PluginContext pluginContext) {
FbpaConfig.getInstance();
}
@Override
public void beforeStop(PluginContext pluginContext) {
}
}

64
src/main/java/com/fr/plugin/fbpa/config/FbpaConfig.java

@ -0,0 +1,64 @@
/*
* Copyright (C), 2018-2021
* Project: starter
* FileName: FbpaConfig
* Author: xx
* Date: 2021/3/30 9:38
*/
package com.fr.plugin.fbpa.config;
import com.fr.config.*;
import com.fr.config.holder.Conf;
import com.fr.config.holder.factory.Holders;
/**
* <Function Description><br>
* <FbpaConfig>
*
* @author xx
* @since 1.0.0
*/
@Visualization(category = "Plugin-fbpa_Group")
public class FbpaConfig extends DefaultConfiguration {
public static final String DEFAULT_LOGIN_URL = "https://xx.com.cn/login";
public static final String DEFAULT_VALIDATE_URL = "https://xx.com.cn/serviceValidate";
public static final String DEFAULT_SERVER_NAME = "xx.com.cn";
private static volatile FbpaConfig config = null;
@Identifier(value = "loginUrl", name = "Plugin-fbpa_Config_LoginUrl", description = "Plugin-fbpa_Config_LoginUrl_Description", status = Status.SHOW)
private final Conf<String> loginUrl = Holders.simple(DEFAULT_LOGIN_URL);
@Identifier(value = "validateUrl", name = "Plugin-fbpa_Config_ValidateUrl", description = "Plugin-fbpa_Config_ValidateUrl_Description", status = Status.SHOW)
private final Conf<String> validateUrl = Holders.simple(DEFAULT_VALIDATE_URL);
@Identifier(value = "serverName", name = "Plugin-fbpa_Config_ServerName", description = "Plugin-fbpa_Config_ServerName_Description", status = Status.SHOW)
private final Conf<String> serverName = Holders.simple(DEFAULT_SERVER_NAME);
public static FbpaConfig getInstance() {
if (config == null) {
config = ConfigContext.getConfigInstance(FbpaConfig.class);
}
return config;
}
public String getLoginUrl() {
return loginUrl.get();
}
public void setLoginUrl(String loginUrl) {
this.loginUrl.set(loginUrl);
}
public String getValidateUrl() {
return validateUrl.get();
}
public void setValidateUrl(String validateUrl) {
this.validateUrl.set(validateUrl);
}
public String getServerName() {
return serverName.get();
}
public void setServerName(String serverName) {
this.serverName.set(serverName);
}
}

133
src/main/java/com/fr/plugin/fbpa/request/IgnoreFilter.java

@ -0,0 +1,133 @@
/*
* Copyright (C), 2018-2022
* Project: starterBI
* FileName: IgnoreFilter
* Author: xx
* Date: 2022/7/5 10:28
*/
package com.fr.plugin.fbpa.request;
import com.fanruan.api.i18n.I18nKit;
import com.fanruan.api.log.LogKit;
import com.fanruan.api.util.StringKit;
import com.fr.base.ServerConfig;
import com.fr.data.NetworkHelper;
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.general.ComparatorUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.plugin.context.PluginContexts;
import com.fr.stable.StringUtils;
import com.fr.web.utils.WebUtils;
import edu.yale.its.tp.cas.client.filter.CASFilter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* <Function Description><br>
* <IgnoreFilter放行请求>
*
* @author xx
* @since 1.0.0
*/
public class IgnoreFilter extends AbstractGlobalRequestFilterProvider {
public static final String VIEW_REPORT = "/view/report";
public static final String VIEW_FORM = "/view/form";
public static final String OP_H5 = "H5";
public static final String MOBILE_PATH = "/url/mobile";
public static final String IGNORE_REQUEST = "ignoreRequest";
/**
* 过滤器名称
*
* @return
*/
@Override
public String filterName() {
return "A_IgnoreFilter";
}
/**
* 过滤规则
*
* @return
*/
@Override
public String[] urlPatterns() {
if (PluginContexts.currentContext() == null || !PluginContexts.currentContext().isAvailable()) {
LogKit.error(I18nKit.getLocText("Plugin-fbpa_Licence_Expired"));
return new String[]{};
}
return new String[]{"/" + ServerConfig.getInstance().getServletName()};
}
/**
* 过滤器初始化
*
* @param filterConfig
*/
@Override
public void init(FilterConfig filterConfig) {
super.init(filterConfig);
}
/**
* 过滤器处理
*
* @param req
* @param res
* @param filterChain
*/
@Override
public void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) {
try {
LogKit.info("fbpa-IgnoreFilter-doFilter-url:{}", WebUtils.getOriginalURL(req));
HttpSession session = req.getSession();
if (LoginService.getInstance().isLogged(req)) {
session.setAttribute(CASFilter.CAS_FILTER_USER, LoginService.getInstance().getCurrentUserNameFromRequestCookie(req));
filterChain.doFilter(req, res);
return;
}
String pathInfo = (req.getPathInfo() != null) ? req.getPathInfo() : StringUtils.EMPTY;
String jsApiPath = NetworkHelper.getHTTPRequestParameter(req, "js_api_path");
String sb = NetworkHelper.getHTTPRequestParameter(req, "sb");
if (ComparatorUtils.equals(VIEW_REPORT, pathInfo) || ComparatorUtils.equals(VIEW_FORM, pathInfo)
|| validateMobile(req, pathInfo)) {
session.setAttribute(CASFilter.CAS_FILTER_USER, IGNORE_REQUEST);
filterChain.doFilter(req, res);
return;
}
if (StringUtils.isNotBlank(jsApiPath) && StringUtils.isNotBlank(sb)) {
LogKit.info("fbpa-IgnoreFilter-doFilter-jsApiPath:{}, sb:{}", jsApiPath, sb);
session.setAttribute(CASFilter.CAS_FILTER_USER, IGNORE_REQUEST);
filterChain.doFilter(req, res);
return;
}
filterChain.doFilter(req, res);
} catch (Exception e) {
LogKit.error(e.getMessage(), e);
}
}
/**
* 验证是否移动端请求
*
* @param req
* @param pathInfo
* @return
*/
private Boolean validateMobile(HttpServletRequest req, String pathInfo) {
String op = WebUtils.getHTTPRequestParameter(req, "op");
return (StringUtils.isNotEmpty(op) && StringUtils.equals(OP_H5, op.toUpperCase()))
|| WebUtils.getDevice(req).isMobile()
|| ComparatorUtils.equalsIgnoreCase(MOBILE_PATH, pathInfo)
|| TerminalHandler.getTerminal(req, WebUtils.getDevice(req)) == TerminalHandler.H5;
}
}

174
src/main/java/com/fr/plugin/fbpa/request/LoginFilter.java

@ -0,0 +1,174 @@
/*
* Copyright (C), 2018-2022
* Project: starterBI
* FileName: LoginFilter
* Author: xx
* Date: 2022/7/5 10:28
*/
package com.fr.plugin.fbpa.request;
import com.fanruan.api.i18n.I18nKit;
import com.fanruan.api.log.LogKit;
import com.fanruan.api.util.StringKit;
import com.fr.base.ServerConfig;
import com.fr.data.NetworkHelper;
import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider;
import com.fr.decision.mobile.terminal.TerminalHandler;
import com.fr.decision.webservice.utils.DecisionServiceConstants;
import com.fr.decision.webservice.v10.login.LoginService;
import com.fr.general.ComparatorUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.plugin.context.PluginContexts;
import com.fr.security.JwtUtils;
import com.fr.stable.StringUtils;
import com.fr.stable.web.Device;
import com.fr.third.org.apache.http.NameValuePair;
import com.fr.third.org.apache.http.client.utils.URIBuilder;
import com.fr.web.utils.WebUtils;
import edu.yale.its.tp.cas.client.filter.CASFilter;
import org.jasig.cas.client.validation.Assertion;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.net.URISyntaxException;
import java.util.List;
import static com.fr.plugin.fbpa.request.IgnoreFilter.IGNORE_REQUEST;
/**
* <Function Description><br>
* <LoginFilter>
*
* @author xx
* @since 1.0.0
*/
public class LoginFilter extends AbstractGlobalRequestFilterProvider {
/**
* 过滤器名称
*
* @return
*/
@Override
public String filterName() {
return "D_LoginFilter";
}
/**
* 过滤规则
*
* @return
*/
@Override
public String[] urlPatterns() {
if (PluginContexts.currentContext() == null || !PluginContexts.currentContext().isAvailable()) {
LogKit.error(I18nKit.getLocText("Plugin-fbpa_Licence_Expired"));
return new String[]{};
}
return new String[]{"/" + ServerConfig.getInstance().getServletName()};
}
/**
* 过滤器初始化
*
* @param filterConfig
*/
@Override
public void init(FilterConfig filterConfig) {
super.init(filterConfig);
}
/**
* 过滤器处理
*
* @param req
* @param res
* @param filterChain
*/
@Override
public void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) {
try {
LogKit.info("fbpa-LoginFilter-doFilter-url:" + WebUtils.getOriginalURL(req));
HttpSession session = req.getSession(true);
String username;
//获取cas传递过来的username
username = req.getRemoteUser();
// Object object = req.getSession().getAttribute("_const_cas_assertion_");
// if (StringUtils.isEmpty(username) && object != null) {
// Assertion assertion = (Assertion) object;
// username = assertion.getPrincipal().getName();
// }
if (StringUtils.isEmpty(username)) {
username = (String) session.getAttribute(CASFilter.CAS_FILTER_USER);
}
if (StringUtils.isEmpty(username)) {
LogKit.info("fbpa-LoginFilter-doFilter-username is Empty");
filterChain.doFilter(req, res);
return;
}
LogKit.info("fbpa-LoginFilter-doFilter-username:{}", username);
// 放行请求
if (StringKit.equalsIgnoreCase(username, IGNORE_REQUEST)) {
session.setAttribute(CASFilter.CAS_FILTER_USER, null);
filterChain.doFilter(req, res);
return;
}
// 决策系统已登录
if (LoginService.getInstance().isLogged(req) && StringKit.equalsIgnoreCase(LoginService.getInstance().getCurrentUserNameFromRequestCookie(req), username)) {
filterChain.doFilter(req, res);
return;
}
login(req, res, session, username);
if (StringUtils.contains(getOriginalURL(req), "ticket")) {
res.sendRedirect(removeToken(req));
return;
}
filterChain.doFilter(req, res);
} catch (Exception e) {
LogKit.error(e.getMessage(), e);
}
}
/**
* 移除url的token参数
*
* @param request
* @return
*/
private String removeToken(HttpServletRequest request) throws URISyntaxException {
URIBuilder uriBuilder = new URIBuilder(getOriginalURL(request));
List<NameValuePair> params = uriBuilder.getQueryParams();
params.removeIf(pair -> ComparatorUtils.equals(pair.getName(), "ticket"));
uriBuilder.clearParameters();
if (!params.isEmpty()) {
uriBuilder.setParameters(params);
}
return uriBuilder.build().toString();
}
/**
* 得到请求url和参数
*
* @param request
* @return
*/
private String getOriginalURL(HttpServletRequest request) {
StringBuffer url = request.getRequestURL();
if (StringUtils.isNotBlank(request.getQueryString())) {
url.append("?").append(request.getQueryString());
}
return url.toString();
}
/**
* 后台登录方法
*/
private void login(HttpServletRequest req, HttpServletResponse res, HttpSession session, String username) throws Exception {
String token = LoginService.getInstance().login(req, res, username);
req.setAttribute(DecisionServiceConstants.FINE_AUTH_TOKEN_NAME, token);
}
}

94
src/main/java/com/fr/plugin/fbpa/request/SSOFilter.java

@ -0,0 +1,94 @@
/*
* Copyright (C), 2018-2021
* Project: starter
* FileName: SSOFilter
* Author: xx
* Date: 2021/12/16 15:01
*/
package com.fr.plugin.fbpa.request;
import com.fanruan.api.i18n.I18nKit;
import com.fanruan.api.log.LogKit;
import com.fr.base.ServerConfig;
import com.fr.decision.fun.GlobalRequestFilterProvider;
import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider;
import com.fr.plugin.context.PluginContexts;
import com.fr.plugin.fbpa.config.FbpaConfig;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
/**
* <Function Description><br>
* <SSOFilter>
*
* @author xx
* @since 1.0.0
*/
public class SSOFilter extends AbstractGlobalRequestFilterProvider {
public static final String LOGIN_URL = "edu.yale.its.tp.cas.client.filter.loginUrl";
public static final String VALIDATE_URL = "edu.yale.its.tp.cas.client.filter.validateUrl";
public static final String SERVER_NAME = "edu.yale.its.tp.cas.client.filter.serverName";
/**
* 过滤器名称
*
* @return
*/
@Override
public String filterName() {
return "B_SSOFilter";
}
/**
* 过滤规则
*
* @return
*/
@Override
public String[] urlPatterns() {
if (PluginContexts.currentContext() == null || !PluginContexts.currentContext().isAvailable()) {
LogKit.error(I18nKit.getLocText("Plugin-fbpa_Licence_Expired"));
return new String[]{};
}
return new String[]{"/" + ServerConfig.getInstance().getServletName()};
}
/**
* 外部的过滤器类名需要把相应的jar包放到web服务器的classpath中
*
* @return 类名
*/
@Override
public String externalFilterClassName() {
return "edu.yale.its.tp.cas.client.filter.CASFilter";
}
/**
* 过滤器的初始化参数
*
* @return 参数集合
*/
@Override
public Map<String, String> initializationParameters() {
Map<String, String> params = new HashMap<>();
FbpaConfig config = FbpaConfig.getInstance();
params.put(LOGIN_URL, config.getLoginUrl());
params.put(VALIDATE_URL, config.getValidateUrl());
params.put(SERVER_NAME, config.getServerName());
return params;
}
/**
* 可选实现的多个filter排序执行顺序的方法
*
* @param other
* @return 0 相等大于0是自身优先 小于0 是other优先
*/
@Override
public int compareTo(@NotNull GlobalRequestFilterProvider other) {
return super.compareTo(other);
}
}

9
src/main/resources/com/fr/plugin/fbpa/locale/lang.properties

@ -0,0 +1,9 @@
Plugin-fbpa=Sso Plugin
Plugin-fbpa_Group=Sso Plugin
Plugin-fbpa_Config_LoginUrl=CAS LoginUrl
Plugin-fbpa_Config_LoginUrl_Description=CAS LoginUrl
Plugin-fbpa_Config_ValidateUrl=CAS ValidateUrl
Plugin-fbpa_Config_ValidateUrl_Description=CAS ValidateUrl
Plugin-fbpa_Config_ServerName=FR url
Plugin-fbpa_Config_ServerName_Description=FR url
Plugin-fbpa_Licence_Expired=Sso Plugin Licence Expired

9
src/main/resources/com/fr/plugin/fbpa/locale/lang_zh_CN.properties

@ -0,0 +1,9 @@
Plugin-fbpa=\u5355\u70B9\u767B\u9646\u63D2\u4EF6
Plugin-fbpa_Group=\u5355\u70B9\u767B\u9646\u63D2\u4EF6
Plugin-fbpa_Config_LoginUrl=CAS\u767B\u9646url
Plugin-fbpa_Config_LoginUrl_Description=CAS\u767B\u9646url
Plugin-fbpa_Config_ValidateUrl=CAS\u9A8C\u8BC1url
Plugin-fbpa_Config_ValidateUrl_Description=CAS\u9A8C\u8BC1url
Plugin-fbpa_Config_ServerName=\u5E06\u8F6F\u7CFB\u7EDFurl
Plugin-fbpa_Config_ServerName_Description=\u5E06\u8F6F\u7CFB\u7EDFurl
Plugin-fbpa_Licence_Expired=\u5355\u70B9\u767B\u9646\u63D2\u4EF6\u8BB8\u53EF\u8FC7\u671F

97
src/main/resources/com/fr/plugin/fbpa/web/unavailable.html

@ -0,0 +1,97 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
body {
background-color: #ffffff;
}
.main {
position: absolute;
top: 25%;
left: 10%;
right: 10%;
margin: auto;
}
.main div {
text-align: center;
}
#header-content {
min-width: 40%;
min-height: 40%;
max-width: 100%;
max-height: 100%;
}
.simple-message {
font-weight: 500;
width: 100%;
font-size: 28px;
color: #3685f2;
text-align: center;
margin-top: 20px;
line-height: 40px;
}
.detail-message {
font-size: 16px;
color: #ff4949;
margin: 15px auto;
line-height: 24px;
}
.solution {
font-size: 16px;
color: #ff4949;
line-height: 24px;
}
.login {
color: #3685f2;
text-decoration: none;
line-height: 24px;
float: right;
height: 24px;
font-size: 12px;
margin-right: 40px;
margin-top: 40px;
}
</style>
<script src="${fineServletURL}/file?path=com.fr.decision.web.i18n.NormalTextGenerator&type=class&parser=plain"
type="text/javascript"></script>
</head>
<body>
<!--<a href="${fineServletURL}/login${origin}" class="login">${switchAccount}</a>-->
<div class="main" id="${errorPageID}">
<div class="simple-message" id="simple-message">${result}</div>
<div class="detail-message" id="detail-message">${reason}</div>
<div class="solution" id="solution">${solution}</div>
</div>
<script>
function getI18n(key) {
var value;
try {
value = (I18n && I18n[key]);
} catch (e) {
value = (FR && FR.i18nText(key))
}
return !value ? key : value;
}
var id = "${errorPageID}";
var simple = document.getElementById(id).children[1];
var detail = document.getElementById(id).children[2];
var solution = document.getElementById(id).children[3];
;
simple.innerText = getI18n(simple.innerText);
detail.innerText = getI18n(detail.innerText);
solution.innerText = getI18n(solution.innerText);
</script>
</body>
</html>
Loading…
Cancel
Save