diff --git a/JSD-9224-需求确认书V1.docx b/JSD-9224-需求确认书V1.docx
new file mode 100644
index 0000000..fe10263
Binary files /dev/null and b/JSD-9224-需求确认书V1.docx differ
diff --git a/README.md b/README.md
index fbe949b..58313bb 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
# open-JSD-9224
-JSD-9224 OAuth2单点
\ No newline at end of file
+JSD-9224 OAuth2单点\
+免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\
+仅作为开发者学习参考使用!禁止用于任何商业用途!\
+为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系hugh处理。
\ No newline at end of file
diff --git a/plugin.xml b/plugin.xml
new file mode 100644
index 0000000..c29a40b
--- /dev/null
+++ b/plugin.xml
@@ -0,0 +1,30 @@
+
+
+ com.fr.plugin.xxxx.gjdbjj.sso
+
+ yes
+ 1.10
+ 10.0
+ 2018-07-31
+ fr.open
+
+
+ [2021-12-27]【1.1】适配原始app。
+ [2021-12-27]【1.2】去掉移动端。
+ [2021-12-27]【1.3】接口修改。
+ [2021-12-28]【1.4】增加接口授权。
+ [2021-12-28]【1.5】接口加载修改。
+ [2021-12-29]【1.6】修改引用。
+ [2021-12-29]【1.7】用户排除和接口返回修改。
+ [2021-12-29]【1.8】返回字段修改。
+ [2021-12-29]【1.9】替换请求数据。
+ [2022-01-10]【1.10】接口修改。
+ ]]>
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/BodyReaderHttpServletRequestWrapper.java b/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/BodyReaderHttpServletRequestWrapper.java
new file mode 100644
index 0000000..e87b3c9
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/BodyReaderHttpServletRequestWrapper.java
@@ -0,0 +1,65 @@
+package com.fr.plugin.xxxx.gjdbjj.sso;
+
+import com.fr.log.FineLoggerFactory;
+import com.fr.third.jodd.io.StreamUtil;
+
+import javax.servlet.ReadListener;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+/**
+ * @author fr.open
+ * @date 2019/7/2
+ */
+public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
+ private BufferedReader br;
+ private byte[] body;
+ public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
+ super(request);
+ //this.br = request.getReader();
+ body = StreamUtil.readBytes(request.getReader(), "UTF-8");
+ FineLoggerFactory.getLogger().info("data is {}",new String(body));
+ }
+
+ public void setBody(byte[] body){
+ this.body =body;
+ }
+
+
+ @Override
+ public BufferedReader getReader() throws IOException {
+ return new BufferedReader(new InputStreamReader(getInputStream()));
+ }
+
+ @Override
+ public ServletInputStream getInputStream() throws IOException {
+ final ByteArrayInputStream bais = new ByteArrayInputStream(body);
+ return new ServletInputStream() {
+
+ @Override
+ public boolean isFinished() {
+ return false;
+ }
+
+ @Override
+ public boolean isReady() {
+ return false;
+ }
+
+ @Override
+ public void setReadListener(ReadListener readListener) {
+
+ }
+
+ @Override
+ public int read() throws IOException {
+ return bais.read();
+ }
+ };
+ }
+}
diff --git a/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/CustomLogInOutEventProvider.java b/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/CustomLogInOutEventProvider.java
new file mode 100644
index 0000000..2d208c4
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/CustomLogInOutEventProvider.java
@@ -0,0 +1,39 @@
+package com.fr.plugin.xxxx.gjdbjj.sso;
+
+import com.fr.decision.fun.impl.AbstractLogInOutEventProvider;
+import com.fr.decision.webservice.login.LogInOutResultInfo;
+import com.fr.general.PropertiesUtils;
+import com.fr.plugin.xxxx.gjdbjj.sso.utils.LogUtils;
+import com.fr.stable.StringUtils;
+import com.fr.third.springframework.web.util.WebUtils;
+
+import javax.servlet.http.Cookie;
+import java.util.Properties;
+
+import static com.fr.plugin.xxxx.gjdbjj.sso.utils.CommonUtils.getProperty;
+
+
+/**
+ * @Author fr.open
+ * @since 2021/8/24
+ **/
+public class CustomLogInOutEventProvider extends AbstractLogInOutEventProvider {
+
+ @Override
+ public String logoutAction(LogInOutResultInfo result) {
+ Cookie token = WebUtils.getCookie(result.getRequest(), "ACCESS_TOKEN");
+ if (token != null) {
+ Properties props = PropertiesUtils.getProperties("sso");
+ String logoutURL = getProperty(props, "api.logout", true);
+ String redirectUri = getProperty(props, "api.redirectUri", true);
+ if (StringUtils.isBlank(logoutURL)) {
+ return StringUtils.EMPTY;
+ }
+ String format = String.format("%s?redirect_uri=%s&access_token=%s", logoutURL, redirectUri, token.getValue());
+ LogUtils.debug4plugin("get logout URL is {}", format);
+ return format;
+ }
+
+ return StringUtils.EMPTY;
+ }
+}
diff --git a/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/LRGT.java b/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/LRGT.java
new file mode 100644
index 0000000..8b2b462
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/LRGT.java
@@ -0,0 +1,28 @@
+package com.fr.plugin.xxxx.gjdbjj.sso;
+
+import com.fr.plugin.context.PluginContext;
+import com.fr.plugin.xxxx.gjdbjj.sso.conf.AuthSsoConfig;
+import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor;
+
+/**
+ * 配置信息初始化
+ */
+
+public class LRGT extends AbstractPluginLifecycleMonitor {
+ @Override
+ public void afterRun(PluginContext pluginContext) {
+ AuthSsoConfig.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/gjdbjj/sso/LoginFilter.java b/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/LoginFilter.java
new file mode 100644
index 0000000..9a3977e
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/LoginFilter.java
@@ -0,0 +1,162 @@
+package com.fr.plugin.xxxx.gjdbjj.sso;
+
+import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider;
+import com.fr.decision.privilege.TransmissionTool;
+import com.fr.decision.webservice.bean.authentication.LoginRequestInfoBean;
+import com.fr.general.PropertiesUtils;
+import com.fr.json.JSONObject;
+import com.fr.log.FineLoggerFactory;
+import com.fr.plugin.context.PluginContexts;
+import com.fr.plugin.xxxx.gjdbjj.sso.utils.HttpUtil;
+import com.fr.plugin.xxxx.gjdbjj.sso.utils.LogUtils;
+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.digest.DigestUtils;
+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.BufferedReader;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.stream.Stream;
+
+import static com.fr.plugin.xxxx.gjdbjj.sso.utils.CommonUtils.next;
+
+
+/**
+ * @author fr.open
+ * @since 2021/12/04
+ */
+@FunctionRecorder
+@Authorize(callSignKey = PluginConstants.PLUGIN_ID)
+public class LoginFilter extends AbstractGlobalRequestFilterProvider {
+
+ private String passLogin;
+
+ private String headerAuth;
+
+ private String extraUser;
+
+ private String tokenInfo;
+
+ private void initParams() {
+ Properties props = PropertiesUtils.getProperties("sso");
+ this.passLogin = props.getProperty("api.passLogin");
+ LogUtils.debug4plugin("get passLogin config is {}", passLogin);
+ this.headerAuth = props.getProperty("api.headerAuth");
+ LogUtils.debug4plugin("get headerAuth config is {}", headerAuth);
+ this.extraUser = props.getProperty("api.extraUser");
+ LogUtils.debug4plugin("get extraUser config is {}", extraUser);
+ this.tokenInfo = props.getProperty("api.tokenInfo");
+ LogUtils.debug4plugin("get tokenInfo config is {}", tokenInfo);
+
+ }
+
+ @Override
+ public void init(FilterConfig filterConfig) {
+ super.init(filterConfig);
+ initParams();
+ }
+
+ @Override
+ public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
+ if (request.getMethod().equals("POST") &&
+ request.getRequestURI().equals("/webroot/decision/login")
+ && WebUtils.getDevice(request).isMobile()
+ ) {
+ try {
+ LogUtils.debug4plugin("current request is mobile request");
+ BodyReaderHttpServletRequestWrapper wrapper = new BodyReaderHttpServletRequestWrapper(request);
+ executeLogin(wrapper, response);
+ next(wrapper, response, chain);
+ return;
+ } catch (IOException e) {
+ LogUtils.error(e.getMessage(), e);
+ }
+ }
+ next(request, response, chain);
+ }
+
+ private void executeLogin(BodyReaderHttpServletRequestWrapper request, HttpServletResponse response) {
+ LoginRequestInfoBean info = getLoginInfo(request);
+ if (StringUtils.isNotBlank(extraUser) && Stream.of(extraUser.split(",")).anyMatch(e -> e.equals(info.getUsername()))) {
+ return;
+ }
+ Map header = new HashMap<>();
+ header.put("Content-Type", "application/x-www-form-urlencoded");
+ header.put("Authorization", "Basic " + headerAuth);
+ HashMap params = new HashMap<>();
+ params.put("password", DigestUtils.md5Hex(info.getPassword()).toLowerCase());
+ params.put("username", info.getUsername());
+ params.put("grant_type", "password");
+ String res = HttpUtil.doFormPost(passLogin, header, params, "UTF-8");
+ LogUtils.debug4plugin("valid password res is {} by param {} to {}", res, params, passLogin);
+ if (StringUtils.isNotBlank(res)) {
+ JSONObject object = new JSONObject(res);
+ if (object.getJSONObject("datas").get("access_token") != null) {
+ String pwd = getLogin(object.getJSONObject("datas").getString("access_token"));
+ info.setPassword(TransmissionTool.encrypt(pwd));
+ request.setBody(JSONObject.mapFrom(info).toString().getBytes(StandardCharsets.UTF_8));
+ }
+ }
+ }
+
+ private String getLogin(String token) {
+ String url = String.format("%s?token=%s", tokenInfo, token);
+ String res = HttpUtil.sendGet(url, null, null);
+ LogUtils.debug4plugin("token info res is {} by {}", res, url);
+ if (StringUtils.isNotBlank(res)) {
+ JSONObject object = new JSONObject(res);
+ if (object.getJSONObject("datas").get("frPwd") != null) {
+ return object.getJSONObject("datas").getString("frPwd");
+ }
+ }
+ return StringUtils.EMPTY;
+ }
+
+ public LoginRequestInfoBean getLoginInfo(HttpServletRequest req) {
+ try {
+ BufferedReader br = req.getReader();
+ String str = "";
+ String listString = "";
+ while ((str = br.readLine()) != null) {
+ listString += str;
+ }
+ JSONObject jsonObject = new JSONObject(listString);
+ LoginRequestInfoBean info = jsonObject.mapTo(LoginRequestInfoBean.class);
+ info.setPassword(TransmissionTool.decrypt(info.isEncrypted(), info.getPassword()));
+ return info;
+ } catch (Exception e) {
+ FineLoggerFactory.getLogger().error(e.getMessage(), e);
+ }
+ return null;
+ }
+
+ @Override
+ public String filterName() {
+ return "gjdbjj";
+ }
+
+ @Override
+ public String[] urlPatterns() {
+ if (PluginContexts.currentContext().isAvailable()) {
+ return new String[]{
+ //"/decision/",
+ "/decision/login",
+ //"/decision",
+ //"/decision/view/report",
+ //"/decision/view/form"
+ };
+ }else {
+ return new String[0];
+ }
+ }
+
+}
diff --git a/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/PluginConstants.java b/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/PluginConstants.java
new file mode 100644
index 0000000..e0a2ec7
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/PluginConstants.java
@@ -0,0 +1,13 @@
+package com.fr.plugin.xxxx.gjdbjj.sso;
+
+/**
+ * @author fr.open
+ * @since 2021/12/04
+ */
+public class PluginConstants {
+
+ public static final String PLUGIN_ID = "com.fr.plugin.xxxx.gjdbjj.sso";
+
+ public static final String PLUGIN_NAME = "Oauth2";
+
+}
diff --git a/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/conf/AuthSsoConfig.java b/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/conf/AuthSsoConfig.java
new file mode 100644
index 0000000..9ad2eaa
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/conf/AuthSsoConfig.java
@@ -0,0 +1,43 @@
+package com.fr.plugin.xxxx.gjdbjj.sso.conf;
+
+import com.fr.config.*;
+import com.fr.config.holder.Conf;
+import com.fr.config.holder.factory.Holders;
+
+
+/**
+ * @author fr.open
+ * @since 2021/12/04
+ */
+@Visualization(category = "Oauth2配置")
+public class AuthSsoConfig extends DefaultConfiguration {
+
+ private static volatile AuthSsoConfig config = null;
+
+ public static AuthSsoConfig getInstance() {
+ if (config == null) {
+ config = ConfigContext.getConfigInstance(AuthSsoConfig.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 {
+ AuthSsoConfig cloned = (AuthSsoConfig) super.clone();
+ cloned.debugSwitch = (Conf) debugSwitch.clone();
+ return cloned;
+ }
+
+
+}
diff --git a/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/utils/CommonUtils.java b/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/utils/CommonUtils.java
new file mode 100644
index 0000000..0e598b7
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/utils/CommonUtils.java
@@ -0,0 +1,132 @@
+package com.fr.plugin.xxxx.gjdbjj.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/gjdbjj/sso/utils/HttpUtil.java b/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/utils/HttpUtil.java
new file mode 100644
index 0000000..b75a141
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/utils/HttpUtil.java
@@ -0,0 +1,327 @@
+package com.fr.plugin.xxxx.gjdbjj.sso.utils;
+
+import com.fr.json.JSONObject;
+import com.fr.log.FineLoggerFactory;
+import com.fr.stable.StringUtils;
+import com.fr.third.org.apache.http.HttpResponse;
+import com.fr.third.org.apache.http.HttpStatus;
+import com.fr.third.org.apache.http.NameValuePair;
+import com.fr.third.org.apache.http.client.HttpClient;
+import com.fr.third.org.apache.http.client.entity.UrlEncodedFormEntity;
+import com.fr.third.org.apache.http.client.methods.HttpPost;
+import com.fr.third.org.apache.http.config.Registry;
+import com.fr.third.org.apache.http.config.RegistryBuilder;
+import com.fr.third.org.apache.http.conn.socket.ConnectionSocketFactory;
+import com.fr.third.org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import com.fr.third.org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import com.fr.third.org.apache.http.impl.client.HttpClients;
+import com.fr.third.org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import com.fr.third.org.apache.http.message.BasicNameValuePair;
+import com.fr.third.org.apache.http.util.EntityUtils;
+
+import javax.net.ssl.*;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+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 doFormPost(String url, Map header, Map map, String chartset) {
+ //声明返回结果
+ String result = "";
+ UrlEncodedFormEntity entity = null;
+ HttpResponse httpResponse = null;
+ HttpClient httpClient = null;
+ try {
+ // 创建连接
+ httpClient = HttpClients.createDefault();
+ ;
+ if (url.startsWith("https")) {
+ SSLContext sslcontext = createIgnoreVerifySSL();
+ Registry socketFactoryRegistry = RegistryBuilder.create()
+ .register("http", PlainConnectionSocketFactory.INSTANCE)
+ .register("https", new SSLConnectionSocketFactory(sslcontext))
+ .build();
+ PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
+ HttpClients.custom().setConnectionManager(connManager);
+ httpClient = HttpClients.custom().setConnectionManager(connManager).build();
+ }
+ // 设置请求头和报文
+ HttpPost httpPost = new HttpPost(url);
+ if (header != null) {
+ header.forEach((k, v) -> {
+ httpPost.setHeader(k, String.valueOf(v));
+ });
+ }
+ //设置参数
+ List list = new ArrayList();
+ Iterator iterator = map.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Map.Entry elem = (Map.Entry) iterator.next();
+ list.add(new BasicNameValuePair(elem.getKey(), elem.getValue()));
+ }
+ entity = new UrlEncodedFormEntity(list, chartset == null ? "UTF-8" : chartset);
+ httpPost.setEntity(entity);
+ //执行发送,获取相应结果
+ httpResponse = httpClient.execute(httpPost);
+ if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+ result = EntityUtils.toString(httpResponse.getEntity());
+ } else {
+ FineLoggerFactory.getLogger().error("Http post form code is {},message is {}", httpResponse.getStatusLine().getStatusCode(), EntityUtils.toString(httpResponse.getEntity()));
+ }
+ } catch (Exception e) {
+ FineLoggerFactory.getLogger().error(e.getMessage(), e);
+ }
+ 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)");
+ if(body != null && !body.isEmpty()){
+ conn.setRequestProperty("Content-Type","application/json;;charset=UTF-8");
+ }
+ 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();
+
+ // 发送请求参数
+ 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;
+ }
+ }
+
+ public static SSLContext createIgnoreVerifySSL() {
+ try {
+ SSLContext sc = SSLContext.getInstance("SSLv3");
+
+ // 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法
+ X509TrustManager trustManager = new X509TrustManager() {
+ @Override
+ public void checkClientTrusted(
+ java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
+ String paramString) throws CertificateException {
+ }
+
+ @Override
+ public void checkServerTrusted(
+ java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
+ String paramString) throws CertificateException {
+ }
+
+ @Override
+ public java.security.cert.X509Certificate[] getAcceptedIssuers() {
+ return null;
+ }
+ };
+
+ sc.init(null, new TrustManager[]{trustManager}, null);
+ return sc;
+ } catch (Exception e) {
+ FineLoggerFactory.getLogger().error(e.getMessage(), e);
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/utils/LogUtils.java b/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/utils/LogUtils.java
new file mode 100644
index 0000000..18e6392
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/gjdbjj/sso/utils/LogUtils.java
@@ -0,0 +1,121 @@
+package com.fr.plugin.xxxx.gjdbjj.sso.utils;
+
+import com.fr.log.FineLoggerFactory;
+import com.fr.log.FineLoggerProvider;
+import com.fr.plugin.context.PluginContexts;
+import com.fr.plugin.xxxx.gjdbjj.sso.conf.AuthSsoConfig;
+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 (AuthSsoConfig.getInstance().getDebugSwitch()) {
+ LOGGER.error(DEBUG_PREFIX + LOG_PREFIX + s);
+ } else {
+ LOGGER.debug(LOG_PREFIX + s);
+ }
+ }
+
+ public static void debug4plugin(String s, Object... objects) {
+ if (AuthSsoConfig.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 (AuthSsoConfig.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/sso.properties b/src/main/resources/sso.properties
new file mode 100644
index 0000000..852ca72
--- /dev/null
+++ b/src/main/resources/sso.properties
@@ -0,0 +1,14 @@
+api.client_id=xxxxxx
+api.client_secret=xxxxxx
+api.authorize=http://127.0.0.1:8080/idp/oauth2/authorize
+api.get-token=http://127.0.0.1:8080/idp/oauth2/getToken
+api.get-user=http://127.0.0.1:8080/idp/oauth2/getUserInfo
+api.redirectUri=http://127.0.0.1:8075/webroot/decision
+api.logout=http://127.0.0.1:8080/idp/profile/OAUTH2/Redirect/GLO
+api.scope=app
+## app login url
+api.passLogin=
+## login header Auth
+api.headerAuth=
+##not sso users
+api.extraUser=