diff --git a/JSD-9151-需求确认书V1.docx b/JSD-9151-需求确认书V1.docx
new file mode 100644
index 0000000..9d992a0
Binary files /dev/null and b/JSD-9151-需求确认书V1.docx differ
diff --git a/JSD-9151配置使用文档.docx b/JSD-9151配置使用文档.docx
new file mode 100644
index 0000000..0e6aaab
Binary files /dev/null and b/JSD-9151配置使用文档.docx differ
diff --git a/README.md b/README.md
index 3410dd8..a0179e2 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
# open-JSD-9151
-JSD-9151 OAuth2单点
\ No newline at end of file
+JSD-9151 OAuth2单点\
+免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\
+仅作为开发者学习参考使用!禁止用于任何商业用途!\
+为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系hugh处理。
\ No newline at end of file
diff --git a/plugin.xml b/plugin.xml
new file mode 100644
index 0000000..debf65e
--- /dev/null
+++ b/plugin.xml
@@ -0,0 +1,25 @@
+
+
+ com.fr.plugin.xxxx.sso
+
+ yes
+ 1.3
+ 10.0
+ 2018-07-31
+ fr.open
+
+
+ [2021-12-16]【1.1】接口调用修改。
+ [2021-12-16]【1.2】禁用用户管理。
+ [2021-12-28]【1.3】非拦截不过滤。
+ ]]>
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/xxxx/sso/LRGT.java b/src/main/java/com/fr/plugin/xxxx/sso/LRGT.java
new file mode 100644
index 0000000..6b0857b
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/sso/LRGT.java
@@ -0,0 +1,28 @@
+package com.fr.plugin.xxxx.sso;
+
+import com.fr.plugin.context.PluginContext;
+import com.fr.plugin.xxxx.sso.conf.ExcelExportConfig;
+import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor;
+
+/**
+ * 配置信息初始化
+ */
+
+public class LRGT extends AbstractPluginLifecycleMonitor {
+ @Override
+ public void afterRun(PluginContext pluginContext) {
+ ExcelExportConfig.getInstance();
+
+ }
+
+ @Override
+ public void beforeStop(PluginContext pluginContext) {
+ }
+ @Override
+ public void beforeUninstall(PluginContext pluginContext) {
+ }
+
+ @Override
+ public void afterInstall(PluginContext var1) {
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/xxxx/sso/PluginConstants.java b/src/main/java/com/fr/plugin/xxxx/sso/PluginConstants.java
new file mode 100644
index 0000000..9cdc093
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/sso/PluginConstants.java
@@ -0,0 +1,11 @@
+package com.fr.plugin.xxxx.sso;
+
+/**
+ * @author fr.open
+ * @since 2021/12/04
+ */
+public interface PluginConstants {
+
+ String PLUGIN_ID = "com.fr.plugin.xxxx.sso";
+
+}
diff --git a/src/main/java/com/fr/plugin/xxxx/sso/conf/ExcelExportConfig.java b/src/main/java/com/fr/plugin/xxxx/sso/conf/ExcelExportConfig.java
new file mode 100644
index 0000000..a7c9a14
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/sso/conf/ExcelExportConfig.java
@@ -0,0 +1,48 @@
+package com.fr.plugin.xxxx.sso.conf;
+
+import com.fr.config.*;
+import com.fr.config.holder.Conf;
+import com.fr.config.holder.factory.Holders;
+import com.fr.intelli.record.Focus;
+import com.fr.intelli.record.Original;
+import com.fr.record.analyzer.EnableMetrics;
+
+
+/**
+ * @author fr.open
+ * @since 2021/12/04
+ */
+@Visualization(category = "Oauth2单点登陆配置")
+@EnableMetrics
+public class ExcelExportConfig extends DefaultConfiguration {
+
+ private static volatile ExcelExportConfig config = null;
+
+ @Focus(id = "com.fr.plugin.xxxx.sso", text = "Oauth2单点登陆配置", source = Original.PLUGIN)
+ public static ExcelExportConfig getInstance() {
+ if (config == null) {
+ config = ConfigContext.getConfigInstance(ExcelExportConfig.class);
+ }
+ return config;
+ }
+
+ @Identifier(value = "debugSwitch", name = "插件调试开关", description = "日志调试模式", status = Status.SHOW)
+ private Conf debugSwitch = Holders.simple(true);
+
+ public Boolean getDebugSwitch() {
+ return this.debugSwitch.get();
+ }
+
+ public void setDebugSwitch(Boolean debugSwitch) {
+ this.debugSwitch.set(debugSwitch);
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ ExcelExportConfig cloned = (ExcelExportConfig) super.clone();
+ cloned.debugSwitch = (Conf) debugSwitch.clone();
+ return cloned;
+ }
+
+
+}
diff --git a/src/main/java/com/fr/plugin/xxxx/sso/filter/CustomLogInOutEventProvider.java b/src/main/java/com/fr/plugin/xxxx/sso/filter/CustomLogInOutEventProvider.java
new file mode 100644
index 0000000..79a08ce
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/sso/filter/CustomLogInOutEventProvider.java
@@ -0,0 +1,33 @@
+package com.fr.plugin.xxxx.sso.filter;
+
+import com.fr.decision.fun.impl.AbstractLogInOutEventProvider;
+import com.fr.decision.webservice.login.LogInOutResultInfo;
+import com.fr.general.PropertiesUtils;
+import com.fr.stable.StringUtils;
+
+import java.util.Properties;
+
+import static com.fr.plugin.xxxx.sso.utils.CommonUtils.getProperty;
+
+
+/**
+ * @Author fr.open
+ * @since 2021/8/24
+ **/
+public class CustomLogInOutEventProvider extends AbstractLogInOutEventProvider {
+
+ @Override
+ public String logoutAction(LogInOutResultInfo result) {
+ Properties props = PropertiesUtils.getProperties("sso");
+ String apiClientId = getProperty(props, "api.client_id", false);
+ String logoutURL = getProperty(props, "api.logout", true);
+ String logoutRedirectURL = getProperty(props, "api.logout.redirect-url", StringUtils.EMPTY, true);
+ if (StringUtils.isBlank(logoutURL)) {
+ return null;
+ }
+ if (StringUtils.isBlank(logoutRedirectURL)) {
+ return String.format("%s?redirectToLogin=false&entityId=%s", logoutURL, apiClientId);
+ }
+ return String.format("%s?redirctToUrl=%s&redirectToLogin=true&entityId=%s", logoutURL, logoutRedirectURL, apiClientId);
+ }
+}
diff --git a/src/main/java/com/fr/plugin/xxxx/sso/filter/SsoFilter.java b/src/main/java/com/fr/plugin/xxxx/sso/filter/SsoFilter.java
new file mode 100644
index 0000000..dbe17b1
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/sso/filter/SsoFilter.java
@@ -0,0 +1,214 @@
+package com.fr.plugin.xxxx.sso.filter;
+
+import com.fr.base.TemplateUtils;
+import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider;
+import com.fr.decision.webservice.bean.authentication.OriginUrlResponseBean;
+import com.fr.decision.webservice.utils.DecisionStatusService;
+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.json.JSONObject;
+import com.fr.locale.InterProviderFactory;
+import com.fr.log.FineLoggerFactory;
+import com.fr.plugin.context.PluginContexts;
+import com.fr.plugin.xxxx.sso.PluginConstants;
+import com.fr.plugin.xxxx.sso.utils.HttpUtil;
+import com.fr.plugin.xxxx.sso.utils.LogUtils;
+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.FilterConfig;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.UUID;
+
+import static com.fr.plugin.xxxx.sso.utils.CommonUtils.*;
+
+
+/**
+ * @author fr.open
+ * @since 2021/12/04
+ */
+@FunctionRecorder
+@Authorize(callSignKey = PluginConstants.PLUGIN_ID)
+public class SsoFilter extends AbstractGlobalRequestFilterProvider {
+
+
+ private String apiClientId;
+
+ private String apiClientSecret;
+
+ private String apiAuthorize;
+
+ private String apiGetToken;
+
+ private String apiGetUser;
+
+ private void initParams() {
+ Properties props = PropertiesUtils.getProperties("sso");
+ this.apiClientId = getProperty(props, "api.client_id", false);
+ this.apiClientSecret = getProperty(props, "api.client_secret", false);
+ this.apiAuthorize = getProperty(props, "api.authorize", false);
+ this.apiGetToken = getProperty(props, "api.get-token", false);
+ this.apiGetUser = getProperty(props, "api.get-user", false);
+ }
+
+ @Override
+ public void init(FilterConfig filterConfig) {
+ super.init(filterConfig);
+ initParams();
+ }
+
+ @Override
+ public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
+ if (isAccept(request) || isLogin(request)) {
+ next(request, response, chain);
+ return;
+ }
+ try {
+ //登录页面跳转地址拦截
+ String origin = WebUtils.getHTTPRequestParameter(request, "origin");
+ if (request.getRequestURI().endsWith("decision/login")) {
+ try {
+ if ("get".equalsIgnoreCase(request.getMethod()) && StringUtils.isNotBlank(origin)) {
+ OriginUrlResponseBean path = DecisionStatusService.originUrlStatusService().get(origin);
+ if (path != null) {
+ String currentPath = String.format("%s://%s:%s%s",request.getScheme(),request.getServerName(),request.getServerPort(),path.getOriginUrl());
+ jumpAuthorize(request, response, currentPath);
+ return;
+ }
+ }
+ } catch (Exception e) {
+ LogUtils.error(e.getMessage(), e);
+ }
+ next(request, response, chain);
+ return;
+ }
+ String code = request.getParameter("code");
+ if (StringUtils.isBlank(code)) {
+ jumpAuthorize(request, response, "");
+ return;
+ }
+ String username = getUsername(getToken(code));
+ login(username, request, response);
+ String state = request.getParameter("state");
+ if (StringUtils.isNotBlank(state)) {
+ String accessURL = getCachedParam(state, "accessURL");
+ if (StringUtils.isNotBlank(accessURL)) {
+ response.sendRedirect(accessURL);
+ return;
+ }
+ }
+ next(request, response, chain);
+ } catch (Exception e) {
+ LogUtils.error("oauth2单点登陆处理失败, Cause by: ", e);
+ setError(response, e.getMessage());
+ }
+ }
+
+ private String getUsername(String token) throws IOException {
+ String address = String.format("%s?access_token=%s&client_id=%s", apiGetUser, token, apiClientId);
+ HashMap params = new HashMap<>();
+ params.put("access_token", token);
+ String res = HttpUtil.sendGet(address, null, null);
+ LogUtils.debug4plugin("请求用户信息返回的内容 >>> [{}]", res);
+ JSONObject body = new JSONObject(res);
+ if (body.has("loginName")) {
+ return body.getString("loginName");
+ }
+ throw new RuntimeException("获取用户信息失败,Cause by: " + res);
+ }
+
+ private String getToken(String code) throws IOException {
+ String address = String.format("%s?client_id=%s&grant_type=authorization_code&code=%s&client_secret=%s", apiGetToken, apiClientId, code, apiClientSecret);
+ HashMap params = new HashMap<>();
+ params.put("client_id", apiClientId);
+ params.put("client_secret", apiClientSecret);
+ params.put("code", code);
+ params.put("grant_type", "authorization_code");
+ String res = HttpUtil.sendPost(address, null, JSONObject.create());
+ LogUtils.debug4plugin("请求 Token 接口返回的内容 >>> [{}]", res);
+ JSONObject body = new JSONObject(res);
+ if (body.has("access_token")) {
+ return body.getString("access_token");
+ }
+ throw new RuntimeException("获取access_token失败,Cause by: " + res);
+ }
+
+ private void jumpAuthorize(HttpServletRequest request, HttpServletResponse response, String originUrl) throws Exception {
+ String state = UUID.randomUUID().toString();
+ String accessURL = request.getRequestURL().toString();
+ Map params = new HashMap<>();
+ if (StringUtils.isNotBlank(originUrl)) {
+ accessURL = String.format("%s://%s:%s%s",request.getScheme(),request.getServerName(),request.getServerPort(), TemplateUtils.render("${fineServletURL}"));;
+ params.put("accessURL", originUrl);
+ } else {
+ if (StringUtils.isNotBlank(request.getQueryString())) {
+ accessURL += "?" + request.getQueryString();
+ }
+ params.put("accessURL", accessURL);
+ }
+ cacheParams(state, params);
+ String address = String.format("%s?redirect_uri=%s&state=%s&client_id=%s&response_type=code", apiAuthorize, URLEncoder.encode(accessURL, "UTF-8"), state, apiClientId);
+ LogUtils.debug4plugin("请求中不包含code值,跳转到登陆页面 >>> \"{}\"", address);
+ response.sendRedirect(address);
+ }
+
+ @Override
+ public String filterName() {
+ return "sso";
+ }
+
+ @Override
+ @Focus(id = PluginConstants.PLUGIN_ID, text = "贵州机场oauth2单点登陆", source = Original.PLUGIN)
+ public String[] urlPatterns() {
+ if (!PluginContexts.currentContext().isAvailable()) {
+ return new String[0];
+ }
+ return new String[]{
+ "/decision/",
+ "/decision/login",
+ "/decision",
+ "/decision/view/report",
+ "/decision/view/form",
+ };
+ }
+
+ private boolean isAccept(HttpServletRequest request) {
+ if (request.getRequestURI().endsWith("/view/form") || request.getRequestURI().endsWith("/view/report")) {
+ if (StringUtils.isNotBlank(WebUtils.getHTTPRequestParameter(request, "code"))) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private void setError(HttpServletResponse res, String reason) {
+ try {
+ PrintWriter printWriter = WebUtils.createPrintWriter(res);
+ Map 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);
+ }
+ }
+
+
+}
diff --git a/src/main/java/com/fr/plugin/xxxx/sso/js/FileDef.java b/src/main/java/com/fr/plugin/xxxx/sso/js/FileDef.java
new file mode 100644
index 0000000..8cf8ce4
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/sso/js/FileDef.java
@@ -0,0 +1,65 @@
+package com.fr.plugin.xxxx.sso.js;
+
+import com.fr.plugin.context.PluginContexts;
+import com.fr.plugin.transform.ExecuteFunctionRecord;
+import com.fr.web.struct.Component;
+import com.fr.web.struct.Filter;
+import com.fr.web.struct.browser.RequestClient;
+import com.fr.web.struct.category.ParserType;
+import com.fr.web.struct.category.ScriptPath;
+import com.fr.web.struct.category.StylePath;
+
+/**
+ * @author fr.open
+ * @date 2019/6/12
+ */
+public class FileDef extends Component {
+ public static final FileDef KEY = new FileDef();
+
+ private FileDef() {
+ }
+
+ /**
+ * 返回需要引入的JS脚本路径
+ *
+ * @param client 请求客户端描述
+ * @return JS脚本路径
+ */
+ @Override
+ public ScriptPath script(RequestClient client) {
+ if(PluginContexts.currentContext().isAvailable()){
+ return ScriptPath.build("/com/fr/plugin/xxxx/sso/main.js", ParserType.DYNAMIC);
+ }else {
+ return ScriptPath.EMPTY;
+ }
+ }
+
+ /**
+ * 返回需要引入的CSS样式路径
+ *
+ * @param client 请求客户端描述
+ * @return CSS样式路径
+ */
+ @Override
+ public StylePath style(RequestClient client) {
+ //如果不需要就直接返回 StylePath.EMPTY;
+ return StylePath.EMPTY;
+ }
+
+ /**
+ * 通过给定的资源过滤器控制是否加载这个资源
+ *
+ * @return 资源过滤器
+ */
+ @ExecuteFunctionRecord
+ @Override
+ public Filter filter() {
+ return new Filter() {
+ @Override
+ public boolean accept() {
+ //任何情况下我们都在平台组件加载时加载我们的组件
+ return true;
+ }
+ };
+ }
+}
diff --git a/src/main/java/com/fr/plugin/xxxx/sso/js/WebResourceProvider.java b/src/main/java/com/fr/plugin/xxxx/sso/js/WebResourceProvider.java
new file mode 100644
index 0000000..1be0554
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/sso/js/WebResourceProvider.java
@@ -0,0 +1,25 @@
+package com.fr.plugin.xxxx.sso.js;
+
+import com.fr.decision.fun.impl.AbstractWebResourceProvider;
+import com.fr.decision.web.MainComponent;
+import com.fr.plugin.transform.FunctionRecorder;
+import com.fr.web.struct.Atom;
+
+/**
+ * @Author fr.open
+ * @Date 2021/10/25
+ * @Description
+ **/
+@FunctionRecorder
+
+public class WebResourceProvider extends AbstractWebResourceProvider {
+ @Override
+ public Atom attach() {
+ return MainComponent.KEY;
+ }
+
+ @Override
+ public Atom client() {
+ return FileDef.KEY;
+ }
+}
diff --git a/src/main/java/com/fr/plugin/xxxx/sso/utils/CommonUtils.java b/src/main/java/com/fr/plugin/xxxx/sso/utils/CommonUtils.java
new file mode 100644
index 0000000..c77845b
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/sso/utils/CommonUtils.java
@@ -0,0 +1,132 @@
+package com.fr.plugin.xxxx.sso.utils;
+
+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/8/24
+ */
+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) {
+ LogUtils.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) {
+ FineLoggerFactory.getLogger().error(e.getMessage(),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, user.getUserName());
+ 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()) {
+ LogUtils.debug4plugin("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])) {
+ LogUtils.debug4plugin("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 values) {
+ try {
+ DecisionStatusService.originUrlStatusService().put(key, values);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static String getCachedParam(String key, String name) {
+ try {
+ Map values = DecisionStatusService.originUrlStatusService().get(key);
+ return values.get(name);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/src/main/java/com/fr/plugin/xxxx/sso/utils/HttpUtil.java b/src/main/java/com/fr/plugin/xxxx/sso/utils/HttpUtil.java
new file mode 100644
index 0000000..f6ec3dc
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/sso/utils/HttpUtil.java
@@ -0,0 +1,237 @@
+package com.fr.plugin.xxxx.sso.utils;
+
+import com.fr.json.JSONObject;
+import com.fr.log.FineLoggerFactory;
+import com.fr.stable.StringUtils;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSession;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @Author fr.open
+ * @Date 2020/12/05
+ * @Description
+ **/
+public class HttpUtil {
+
+ private static HostnameVerifier hv = new HostnameVerifier() {
+ @Override
+ public boolean verify(String urlHostName, SSLSession session) {
+ System.out.println("Warning: URL Host: " + urlHostName + " vs. "
+ + session.getPeerHost());
+ return true;
+ }
+ };
+
+ /**
+ * 发送get请求
+ *
+ * @param url
+ * @param param
+ * @param header
+ * @return
+ * @throws IOException
+ */
+ public static String sendGet(String url, Map param, Map header) {
+ String result = "";
+ BufferedReader in = null;
+ String urlNameString = url;
+ try {
+ if (param != null) {
+ urlNameString += "?";
+ urlNameString += param.entrySet()
+ .stream()
+ .map(entry -> entry.getKey() + "=" + entry.getValue())
+ .collect(Collectors.joining("&"));
+ }
+
+ URL realUrl = new URL(urlNameString);
+ // 打开和URL之间的连接
+ HttpURLConnection connection;
+ if (url.startsWith("https")) {
+ trustAllHttpsCertificates();
+ HttpsURLConnection.setDefaultHostnameVerifier(hv);
+ connection = (HttpURLConnection) realUrl.openConnection();
+ } else {
+ connection = (HttpURLConnection) realUrl.openConnection();
+ }
+ //设置超时时间
+ connection.setDoInput(true);
+ connection.setRequestMethod("GET");
+ connection.setConnectTimeout(5000);
+ connection.setReadTimeout(15000);
+ // 设置通用的请求属性
+ if (header != null) {
+ Iterator> it = header.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry entry = it.next();
+ System.out.println(entry.getKey() + ":::" + entry.getValue());
+ connection.setRequestProperty(entry.getKey(), entry.getValue());
+ }
+ }
+ connection.setRequestProperty("accept", "*/*");
+ connection.setRequestProperty("connection", "Keep-Alive");
+ connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
+ // 建立实际的连接
+ connection.connect();
+ // 定义 BufferedReader输入流来读取URL的响应,设置utf8防止中文乱码
+ in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
+ String line;
+ while ((line = in.readLine()) != null) {
+ result += line;
+ }
+ if (in != null) {
+ in.close();
+ }
+ }catch (Exception e){
+ FineLoggerFactory.getLogger().error(e,"get url error ,url is:{},error is {}",urlNameString,e.getMessage());
+ }
+ return result;
+ }
+
+ public static String sendPost(String url,Map header, JSONObject body) {
+ PrintWriter out = null;
+ BufferedReader in = null;
+ String result = StringUtils.EMPTY;
+ String res = StringUtils.EMPTY;
+ try {
+ String urlNameString = url;
+
+ URL realUrl = new URL(urlNameString);
+ // 打开和URL之间的连接
+ HttpURLConnection conn;
+ if (url.startsWith("https")) {
+ trustAllHttpsCertificates();
+ HttpsURLConnection.setDefaultHostnameVerifier(hv);
+ conn = (HttpURLConnection) realUrl.openConnection();
+ } else {
+ conn = (HttpURLConnection) realUrl.openConnection();
+ }
+ // 设置通用的请求属性
+ conn.setRequestProperty("accept", "*/*");
+ conn.setRequestProperty("connection", "Keep-Alive");
+ conn.setRequestProperty("user-agent",
+ "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
+ conn.setRequestProperty("Content-Type","application/json;;charset=UTF-8");
+ //conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=----footfoodapplicationrequestnetwork");
+ if(header != null){
+ header.forEach((k, v) -> {
+ conn.setRequestProperty(k, v);
+ });
+ }
+ // 发送POST请求必须设置如下两行
+ conn.setDoOutput(true);
+ conn.setDoInput(true);
+ //获取请求头
+
+ // 获取URLConnection对象对应的输出流
+ out = new PrintWriter(conn.getOutputStream());
+ StringBuffer buffer = new StringBuffer();
+ /*param.forEach((k,v)->{
+ buffer.append("------footfoodapplicationrequestnetwork\r\n");
+ buffer.append("Content-Disposition: form-data; name=\"");
+ buffer.append(k);
+ buffer.append("\"\r\n\r\n");
+ buffer.append(v);
+ buffer.append("\r\n");
+ });
+ buffer.append("------footfoodapplicationrequestnetwork--\r\n");
+ out.print(buffer.toString());*/
+ // 发送请求参数
+ if(body != null){
+ out.print(body.toString());
+ }
+ // flush输出流的缓冲
+ out.flush();
+ // 定义BufferedReader输入流来读取URL的响应
+ in = new BufferedReader(
+ new InputStreamReader(conn.getInputStream()));
+ String line;
+ while ((line = in.readLine()) != null) {
+ result += line;
+ }
+ res = result;
+ } catch (Exception e) {
+ FineLoggerFactory.getLogger().error(e.getMessage(),e);
+ }
+ //使用finally块来关闭输出流、输入流
+ finally{
+ try{
+ if(out!=null){
+ out.close();
+ }
+ if(in!=null){
+ in.close();
+ }
+ }
+ catch(IOException e){
+ FineLoggerFactory.getLogger().error(e.getMessage(),e);
+ }
+ }
+ return res;
+ }
+
+ private static void trustAllHttpsCertificates() throws Exception {
+ javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];
+ javax.net.ssl.TrustManager tm = new miTM();
+ trustAllCerts[0] = tm;
+ javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext.getInstance("SSL","SunJSSE");
+ sc.init(null, trustAllCerts, null);
+ HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+ }
+
+
+ /**
+ * encode url by UTF-8
+ * @param url url before encoding
+ * @return url after encoding
+ */
+ public static String encodeUrl(String url){
+ String eurl = url;
+ try {
+ eurl = URLEncoder.encode(url,"UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ }
+ return eurl;
+ }
+
+ private static class miTM implements javax.net.ssl.TrustManager,
+ javax.net.ssl.X509TrustManager {
+ @Override
+ public java.security.cert.X509Certificate[] getAcceptedIssuers() {
+ return null;
+ }
+
+ public boolean isServerTrusted(
+ java.security.cert.X509Certificate[] certs) {
+ return true;
+ }
+
+ public boolean isClientTrusted(
+ java.security.cert.X509Certificate[] certs) {
+ return true;
+ }
+
+ @Override
+ public void checkServerTrusted(
+ java.security.cert.X509Certificate[] certs, String authType)
+ throws java.security.cert.CertificateException {
+ return;
+ }
+
+ @Override
+ public void checkClientTrusted(
+ java.security.cert.X509Certificate[] certs, String authType)
+ throws java.security.cert.CertificateException {
+ return;
+ }
+ }
+}
diff --git a/src/main/java/com/fr/plugin/xxxx/sso/utils/LogUtils.java b/src/main/java/com/fr/plugin/xxxx/sso/utils/LogUtils.java
new file mode 100644
index 0000000..555dee6
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/sso/utils/LogUtils.java
@@ -0,0 +1,121 @@
+package com.fr.plugin.xxxx.sso.utils;
+
+import com.fr.log.FineLoggerFactory;
+import com.fr.log.FineLoggerProvider;
+import com.fr.plugin.context.PluginContexts;
+import com.fr.plugin.xxxx.sso.conf.ExcelExportConfig;
+import com.fr.stable.StringUtils;
+
+/**
+ * @author fr.open
+ * @since 2021/12/04
+ */
+public final class LogUtils {
+ private static final String DEBUG_PREFIX = "[插件调试] ";
+ private static String LOG_PREFIX = "[OAUTH2单点登陆] ";
+ private static final String PLUGIN_VERSION;
+
+ private static final FineLoggerProvider LOGGER = FineLoggerFactory.getLogger();
+
+ static {
+ String version = PluginContexts.currentContext().getMarker().getVersion();
+ if (StringUtils.isNotBlank(version)) {
+ PLUGIN_VERSION = "[v" + version + "] ";
+ } else {
+ PLUGIN_VERSION = "[unknown version] ";
+ }
+
+ LOG_PREFIX = LOG_PREFIX + PLUGIN_VERSION;
+ }
+
+ public static void setPrefix(String prefix) {
+ if (prefix != null) {
+ LOG_PREFIX = prefix;
+ }
+ }
+
+ public static boolean isDebugEnabled() {
+ return LOGGER.isDebugEnabled();
+ }
+
+ public static void debug(String s) {
+ LOGGER.debug(LOG_PREFIX + s);
+ }
+
+ public static void debug(String s, Object... objects) {
+ LOGGER.debug(LOG_PREFIX + s, objects);
+ }
+
+ public static void debug(String s, Throwable throwable) {
+ LOGGER.debug(LOG_PREFIX + s, throwable);
+ }
+
+ public static void debug4plugin(String s) {
+ if (ExcelExportConfig.getInstance().getDebugSwitch()) {
+ LOGGER.error(DEBUG_PREFIX + LOG_PREFIX + s);
+ } else {
+ LOGGER.debug(LOG_PREFIX + s);
+ }
+ }
+
+ public static void debug4plugin(String s, Object... objects) {
+ if (ExcelExportConfig.getInstance().getDebugSwitch()) {
+ LOGGER.error(DEBUG_PREFIX + LOG_PREFIX + s, objects);
+ } else {
+ LOGGER.debug(LOG_PREFIX + s, objects);
+ }
+ }
+
+ public static void debug4plugin(String s, Throwable throwable) {
+ if (ExcelExportConfig.getInstance().getDebugSwitch()) {
+ LOGGER.error(DEBUG_PREFIX + LOG_PREFIX + s, throwable);
+ } else {
+ LOGGER.debug(LOG_PREFIX + s, throwable);
+ }
+ }
+
+
+ public static boolean isInfoEnabled() {
+ return LOGGER.isInfoEnabled();
+ }
+
+ public static void info(String s) {
+ LOGGER.info(LOG_PREFIX + s);
+ }
+
+ public static void info(String s, Object... objects) {
+ LOGGER.info(LOG_PREFIX + s, objects);
+ }
+
+ public static void warn(String s) {
+ LOGGER.warn(LOG_PREFIX + s);
+ }
+
+ public static void warn(String s, Object... objects) {
+ LOGGER.warn(LOG_PREFIX + s, objects);
+ }
+
+ public static void warn(String s, Throwable throwable) {
+ LOGGER.warn(LOG_PREFIX + s, throwable);
+ }
+
+ public static void warn(Throwable throwable, String s, Object... objects) {
+ LOGGER.warn(throwable, LOG_PREFIX + s, objects);
+ }
+
+ public static void error(String s) {
+ LOGGER.error(LOG_PREFIX + s);
+ }
+
+ public static void error(String s, Object... objects) {
+ LOGGER.error(LOG_PREFIX + s, objects);
+ }
+
+ public static void error(String s, Throwable throwable) {
+ LOGGER.error(LOG_PREFIX + s, throwable);
+ }
+
+ public static void error(Throwable throwable, String s, Object... objects) {
+ LOGGER.error(throwable, LOG_PREFIX + s, objects);
+ }
+}
diff --git a/src/main/resources/com/fr/plugin/xxxx/sso/main.js b/src/main/resources/com/fr/plugin/xxxx/sso/main.js
new file mode 100644
index 0000000..fd09373
--- /dev/null
+++ b/src/main/resources/com/fr/plugin/xxxx/sso/main.js
@@ -0,0 +1,18 @@
+/*
+BI.Plugin.registerObject("dec.user.row.tools", function (widget) {
+ widget.element.empty();
+});
+
+BI.config("dec.users.operations.import",function( widget ){
+ //把type: "dec.user.account.setting.item"的去掉
+ widget.element.empty();
+});
+BI.config("dec.users.operations.sync",function( widget ){
+ //把type: "dec.user.account.setting.item"的去掉
+ widget.element.empty();
+});
+
+BI.config("dec.users.operations.add",function( widget ){
+ //把type: "dec.user.account.setting.item"的去掉
+ widget.element.empty();
+});*/
diff --git a/src/main/resources/sso.properties b/src/main/resources/sso.properties
new file mode 100644
index 0000000..07e76d9
--- /dev/null
+++ b/src/main/resources/sso.properties
@@ -0,0 +1,9 @@
+api.client_id=xxxxxx
+api.client_secret=xxxxxx
+api.authorize=https://xxxx/oauth2/authorize
+api.get-token=https://xxxx/oauth2/getToken
+api.get-user=https://xxxx/oauth2/getUserInfo
+api.logout=https://xxxx/profile/OAUTH2/Redirect/GLO
+#\u767B\u51FA\u540E\u8DF3\u8F6C\u9875\u9762\uFF0C\u53EF\u4EE5\u4E3A\u7A7A
+#\u4E3A\u7A7A\u65F6\u505C\u7559\u5728 idp \u9000\u51FA\u5C55\u793A\u9875\u9762
+api.logout.redirect-url=https://www.baidu.com
\ No newline at end of file