commit 459f8f4fd670773edfc971c8544ae51bdcde1dbc Author: pioneer Date: Thu Sep 22 14:00:53 2022 +0800 open diff --git a/README.md b/README.md new file mode 100644 index 0000000..d7be761 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ + +# open-JSD-9151 + +JSD-9151 ouath2.0单点\ +免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\ +仅作为开发者学习参考使用!禁止用于任何商业用途!\ +为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系【pioneer】处理。 \ No newline at end of file diff --git a/doc/JSD-9151配置使用文档.docx b/doc/JSD-9151配置使用文档.docx new file mode 100644 index 0000000..0e6aaab Binary files /dev/null and b/doc/JSD-9151配置使用文档.docx differ diff --git a/plugin.xml b/plugin.xml new file mode 100755 index 0000000..4a4df5d --- /dev/null +++ b/plugin.xml @@ -0,0 +1,30 @@ + + + com.fr.plugin.xxx.gzjc.sso + + yes + 1.8 + 10.0 + 2018-07-31 + fr.open + + + [2021-12-16]【1.1】接口调用修改。
+ [2021-12-16]【1.2】禁用用户管理。
+ [2021-12-28]【1.3】非拦截不过滤。
+ [2021-01-19]【1.4】配置读取修改。
+ [2021-01-20]【1.5】配置读取修改。
+ [2021-01-20]【1.6】未授权报错问题。
+ [2022-06-29]【1.7】增加spRoleList。
+ [2022-07-14]【1.8】修改无用户提示页面。
+ ]]>
+ + + + + + + + +
\ No newline at end of file diff --git a/src/main/java/com/fr/plugin/xxx/gzjc/sso/LRGT.java b/src/main/java/com/fr/plugin/xxx/gzjc/sso/LRGT.java new file mode 100644 index 0000000..d29fd13 --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/gzjc/sso/LRGT.java @@ -0,0 +1,28 @@ +package com.fr.plugin.xxx.gzjc.sso; + +import com.fr.plugin.context.PluginContext; +import com.fr.plugin.xxx.gzjc.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/xxx/gzjc/sso/PluginConstants.java b/src/main/java/com/fr/plugin/xxx/gzjc/sso/PluginConstants.java new file mode 100644 index 0000000..f88b15b --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/gzjc/sso/PluginConstants.java @@ -0,0 +1,10 @@ +package com.fr.plugin.xxx.gzjc.sso; + +/** + * @author xxx + * @since 2021/12/04 + */ +public interface PluginConstants { + + String PLUGIN_ID = "com.fr.plugin.xxx.gzjc.sso"; +} diff --git a/src/main/java/com/fr/plugin/xxx/gzjc/sso/conf/ExcelExportConfig.java b/src/main/java/com/fr/plugin/xxx/gzjc/sso/conf/ExcelExportConfig.java new file mode 100644 index 0000000..ab8a249 --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/gzjc/sso/conf/ExcelExportConfig.java @@ -0,0 +1,48 @@ +package com.fr.plugin.xxx.gzjc.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 xxx + * @since 2021/12/04 + */ +@Visualization(category = "Oauth2单点登陆配置") +@EnableMetrics +public class ExcelExportConfig extends DefaultConfiguration { + + private static volatile ExcelExportConfig config = null; + + @Focus(id = "com.fr.plugin.xxx.gzjc.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/xxx/gzjc/sso/filter/CustomLogInOutEventProvider.java b/src/main/java/com/fr/plugin/xxx/gzjc/sso/filter/CustomLogInOutEventProvider.java new file mode 100644 index 0000000..dd1c005 --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/gzjc/sso/filter/CustomLogInOutEventProvider.java @@ -0,0 +1,33 @@ +package com.fr.plugin.xxx.gzjc.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.xxx.gzjc.sso.utils.CommonUtils.getProperty; + + +/** + * @Author xxx + * @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/xxx/gzjc/sso/filter/SsoFilter.java b/src/main/java/com/fr/plugin/xxx/gzjc/sso/filter/SsoFilter.java new file mode 100644 index 0000000..9b8fb38 --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/gzjc/sso/filter/SsoFilter.java @@ -0,0 +1,232 @@ +package com.fr.plugin.xxx.gzjc.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.JSONArray; +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.xxx.gzjc.sso.PluginConstants; +import com.fr.plugin.xxx.gzjc.sso.utils.HttpUtil; +import com.fr.plugin.xxx.gzjc.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.xxx.gzjc.sso.utils.CommonUtils.*; + + +/** + * @author xxx + * @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 String errorUrl; + + private String appName; + + private void initParams() { + Properties props = PropertiesUtils.getProperties("sso"); + this.apiClientId = props.getProperty("api.client_id"); + this.apiClientSecret = props.getProperty("api.client_secret"); + this.apiAuthorize = props.getProperty("api.authorize"); + this.apiGetToken = props.getProperty("api.get-token"); + this.apiGetUser = props.getProperty("api.get-user"); + this.appName = props.getProperty("api.app-name"); + this.errorUrl = props.getProperty("api.error-url"); + } + + @Override + public void init(FilterConfig filterConfig) { + super.init(filterConfig); + } + + @Override + public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) { + if (isAccept(request) || isLogin(request)) { + next(request, response, chain); + return; + } + try { + initParams(); + //登录页面跳转地址拦截 + 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)); + if(!existUser(username)){ + String address = String.format("%s?systemName=%s&reason=%s", errorUrl, URLEncoder.encode(appName,"UTF-8"), URLEncoder.encode("用户不存在","UTF-8")); + response.sendRedirect(address); + return; + } + 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("spRoleList")){ + JSONArray array = body.getJSONArray("spRoleList"); + if(array.length() != 0){ + return array.getString(0); + } + } + 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[]{"/neverbeused"}; + } + 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/xxx/gzjc/sso/js/FileDef.java b/src/main/java/com/fr/plugin/xxx/gzjc/sso/js/FileDef.java new file mode 100644 index 0000000..a81ee78 --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/gzjc/sso/js/FileDef.java @@ -0,0 +1,65 @@ +package com.fr.plugin.xxx.gzjc.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 xxx + * @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/xxx/gzjc/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/xxx/gzjc/sso/js/WebResourceProvider.java b/src/main/java/com/fr/plugin/xxx/gzjc/sso/js/WebResourceProvider.java new file mode 100644 index 0000000..88af33e --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/gzjc/sso/js/WebResourceProvider.java @@ -0,0 +1,25 @@ +package com.fr.plugin.xxx.gzjc.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 hujian + * @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/xxx/gzjc/sso/utils/CommonUtils.java b/src/main/java/com/fr/plugin/xxx/gzjc/sso/utils/CommonUtils.java new file mode 100644 index 0000000..cb0eeaf --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/gzjc/sso/utils/CommonUtils.java @@ -0,0 +1,146 @@ +package com.fr.plugin.xxx.gzjc.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 xxx + * @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 boolean existUser(String username){ + try { + User user = UserService.getInstance().getUserByUserName(username); + if (user == null) { + return false; + } + return true; + } catch (Exception e) { + + } + return false; + + } + + 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/xxx/gzjc/sso/utils/HttpUtil.java b/src/main/java/com/fr/plugin/xxx/gzjc/sso/utils/HttpUtil.java new file mode 100644 index 0000000..5a135db --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/gzjc/sso/utils/HttpUtil.java @@ -0,0 +1,237 @@ +package com.fr.plugin.xxx.gzjc.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 xxx + * @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/xxx/gzjc/sso/utils/LogUtils.java b/src/main/java/com/fr/plugin/xxx/gzjc/sso/utils/LogUtils.java new file mode 100644 index 0000000..98cb31c --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/gzjc/sso/utils/LogUtils.java @@ -0,0 +1,121 @@ +package com.fr.plugin.xxx.gzjc.sso.utils; + +import com.fr.log.FineLoggerFactory; +import com.fr.log.FineLoggerProvider; +import com.fr.plugin.context.PluginContexts; +import com.fr.plugin.xxx.gzjc.sso.conf.ExcelExportConfig; +import com.fr.stable.StringUtils; + +/** + * @author xxx + * @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/xxx/gzjc/sso/main.js b/src/main/resources/com/fr/plugin/xxx/gzjc/sso/main.js new file mode 100644 index 0000000..fd09373 --- /dev/null +++ b/src/main/resources/com/fr/plugin/xxx/gzjc/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..7880aae --- /dev/null +++ b/src/main/resources/sso.properties @@ -0,0 +1,12 @@ +api.client_id=xxxxxx +api.client_secret=xxxxxx +api.authorize=https://127.0.0.1:8080/idp/oauth2/authorize +api.get-token=https://127.0.0.1:8080/idp/oauth2/getToken +api.get-user=https://127.0.0.1:8080/idp/oauth2/getUserInfo +api.logout=https://127.0.0.1:8080/idp/profile/OAUTH2/Redirect/GLO + +api.logout.redirect-url=https://www.baidu.com + +api.app-name= + +api.error-url= \ No newline at end of file