commit daa061aaa5eae9fd3b835ef15d9dd1d9aa860836 Author: pioneer Date: Tue Nov 8 15:15:41 2022 +0800 open diff --git a/README.md b/README.md new file mode 100644 index 0000000..cc2b0e3 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ + +# open-JSD-9872 + +JSD-9872 SSO单点集成\ +免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\ +仅作为开发者学习参考使用!禁止用于任何商业用途!\ +为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系【pioneer】处理。 \ No newline at end of file diff --git a/lib/finekit-10.0-20220427.jar b/lib/finekit-10.0-20220427.jar new file mode 100644 index 0000000..6793f18 Binary files /dev/null and b/lib/finekit-10.0-20220427.jar differ diff --git a/plugin.xml b/plugin.xml new file mode 100644 index 0000000..da4cfee --- /dev/null +++ b/plugin.xml @@ -0,0 +1,24 @@ + + + com.eco.plugin.zzl.oauth2.mt + + yes + 1.10.5 + 10.0 + 2021-02-10 + fr.open + com.fr.plugin + + + + 2022-5-10 17:03:49 + + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/FunctionRecoder.java b/src/main/java/com/fr/plugin/FunctionRecoder.java new file mode 100644 index 0000000..963ca84 --- /dev/null +++ b/src/main/java/com/fr/plugin/FunctionRecoder.java @@ -0,0 +1,12 @@ +package com.fr.plugin; + +import com.fr.plugin.transform.ExecuteFunctionRecord; +import com.fr.plugin.transform.FunctionRecorder; + +@FunctionRecorder +public class FunctionRecoder { + @ExecuteFunctionRecord + public void exe(){ + System.out.println("插件功能埋点,虽然不会执行,除非上架应用"); + } +} diff --git a/src/main/java/com/fr/plugin/MTConfig.java b/src/main/java/com/fr/plugin/MTConfig.java new file mode 100644 index 0000000..0d3524f --- /dev/null +++ b/src/main/java/com/fr/plugin/MTConfig.java @@ -0,0 +1,81 @@ +package com.fr.plugin; + +import com.fr.config.*; +import com.fr.config.holder.Conf; +import com.fr.config.holder.factory.Holders; + +@Visualization(category = "xx单点配置") +public class MTConfig extends DefaultConfiguration { + + private static volatile MTConfig config = null; + + public static MTConfig getInstance() { + if (config == null) { + config = ConfigContext.getConfigInstance(MTConfig.class); + } + return config; + } + + @Identifier(value = "clientId", name = "clientId", description = "描述", status = Status.SHOW) + private Conf clientId = Holders.simple(""); + @Identifier(value = "clientSecret", name = "clientSecret", description = "描述", status = Status.SHOW) + private Conf clientSecret = Holders.simple(""); + @Identifier(value = "notExistUrl", name = "用户不存在调整地址", description = "用户不存在调整地址URL", status = Status.SHOW) + private Conf notExistUrl = Holders.simple("https://xx/bi/has-error?message=%22%E7%94%A8%E6%88%B7%E4%B8%8D%E5%AD%98%E5%9C%A8%22"); + @Identifier(value = "apiUrl", name = "接口地址", description = "描述", status = Status.SHOW) + private Conf apiUrl = Holders.simple(""); + @Identifier(value = "frUrl", name = "fr地址", description = "描述", status = Status.SHOW) + private Conf frUrl = Holders.simple("http://localhost:8080/webroot/decision/"); + + public String getNotExistUrl() { + return notExistUrl.get(); + } + + public void setNotExistUrl( String notExistUrl) { + this.notExistUrl .set(notExistUrl); + } + + public String getClientId() { + return clientId.get(); + } + + public void setClientId(String clientId) { + this.clientId.set(clientId); + } + + public String getClientSecret() { + return clientSecret.get(); + } + + public void setClientSecret(String clientSecret) { + this.clientSecret.set(clientSecret); + } + + public String getApiUrl() { + return apiUrl.get(); + } + + public void setApiUrl(String apiUrl) { + this.apiUrl.set(apiUrl); + } + + public String getFrUrl() { + return frUrl.get(); + } + + public void setFrUrl(String frUrl) { + this.frUrl.set(frUrl); + } + + @Override + public Object clone() throws CloneNotSupportedException { + MTConfig cloned = (MTConfig) super.clone(); + cloned.clientId = (Conf) this.clientId.clone(); + cloned.clientSecret = (Conf) this.clientSecret.clone(); + cloned.apiUrl = (Conf) this.apiUrl.clone(); + cloned.frUrl = (Conf) this.frUrl.clone(); + cloned.notExistUrl = (Conf) this.notExistUrl.clone(); + return cloned; + } + +} \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/MTLifeCycleMonitor.java b/src/main/java/com/fr/plugin/MTLifeCycleMonitor.java new file mode 100644 index 0000000..4415772 --- /dev/null +++ b/src/main/java/com/fr/plugin/MTLifeCycleMonitor.java @@ -0,0 +1,18 @@ +package com.fr.plugin; + +import com.fr.plugin.context.PluginContext; +import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor; +import com.fr.stable.fun.Authorize; + +@Authorize +public class MTLifeCycleMonitor extends AbstractPluginLifecycleMonitor { + @Override + public void afterRun(PluginContext pluginContext) { + MTConfig.getInstance(); + } + + @Override + public void beforeStop(PluginContext pluginContext) { + + } +} diff --git a/src/main/java/com/fr/plugin/SsoHttpUtil.java b/src/main/java/com/fr/plugin/SsoHttpUtil.java new file mode 100644 index 0000000..889cec3 --- /dev/null +++ b/src/main/java/com/fr/plugin/SsoHttpUtil.java @@ -0,0 +1,100 @@ +package com.fr.plugin; + + +import com.fr.json.JSONObject; +import com.fr.third.org.apache.http.client.methods.CloseableHttpResponse; +import com.fr.third.org.apache.http.client.methods.HttpGet; +import com.fr.third.org.apache.http.impl.client.CloseableHttpClient; +import com.fr.third.org.apache.http.impl.client.HttpClients; +import com.fr.third.org.apache.http.util.EntityUtils; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; + +public class SsoHttpUtil { + private static String publicKey = ""; + + public static String getPublicKey() { + return publicKey; + } + + + public static void initPublicKey() throws IOException { + publicKey = getPublickey(); + } + + /** + * @return 公钥 publickey + */ + public static String getPublickey() throws IOException { + MTConfig mtConfig = MTConfig.getInstance(); + String apiUrl = mtConfig.getApiUrl(); + String clientId = mtConfig.getClientId(); + String clientSecret = mtConfig.getClientSecret(); + + String url = apiUrl + "/fedauth/api/publickey"; + HttpGet httpGet = new HttpGet(url); + + // 设置header + String baUri = "/fedauth/api/publickey"; + Map map = SsoHttpUtil.getSignedHeaders("GET", baUri, clientId, clientSecret); + httpGet.addHeader("Authorization", map.get("Authorization")); + httpGet.addHeader("Content-Type", map.get("Content-Type")); + httpGet.addHeader("Date", map.get("Date")); + CloseableHttpClient httpClient = HttpClients.createDefault(); + + CloseableHttpResponse response = httpClient.execute(httpGet); + if (response.getStatusLine().getStatusCode() == 200) { + String responseString = EntityUtils.toString(response.getEntity(), "utf-8"); + JSONObject jsonObject = new JSONObject(responseString); + JSONObject data = jsonObject.getJSONObject("data"); + return data.getString("publicKey"); + } + return null; + } + + public static Map getSignedHeaders(String method, String uri, String key, String token) { + String date = BaUtil.getAuthDate(new Date()); + method = method.toUpperCase(); + String authorization = BaUtil.getAuthorization(uri, method, date, key, token); + Map headers = new HashMap<>(); + headers.put("Authorization", authorization); + headers.put("Content-Type", "application/json"); + headers.put("Date", date); + return headers; + } + + private static class BaUtil { + public static String getAuthDate(Date date) { + DateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH); + df.setTimeZone(TimeZone.getTimeZone("GMT")); + return df.format(date); + } + + public static String getAuthorization(String uri, String method, String date, String clientId, String secret) { + String stringToSign = method + " " + uri + "\n" + date; + String signature = getSignature(stringToSign, secret); + String authorization = "MWS " + clientId + ":" + signature; + return authorization; + } + + public static String getSignature(String data, String secret) { + try { + SecretKeySpec signingKey = new SecretKeySpec(secret.getBytes(), "HmacSHA1"); + Mac mac = Mac.getInstance("HmacSHA1"); + mac.init(signingKey); + byte[] rawHmac = mac.doFinal(data.getBytes()); + String result = Base64.getEncoder().encodeToString(rawHmac); + result = result.replaceAll("\r|\n", ""); + return result; + } catch (Exception var6) { + throw new RuntimeException("Failed to generate HMAC : " + var6.getMessage()); + } + } + } + +} diff --git a/src/main/java/com/fr/plugin/TicketUtil.java b/src/main/java/com/fr/plugin/TicketUtil.java new file mode 100644 index 0000000..f867e82 --- /dev/null +++ b/src/main/java/com/fr/plugin/TicketUtil.java @@ -0,0 +1,156 @@ +package com.fr.plugin; + + +import com.fr.third.org.apache.commons.codec.digest.DigestUtils; + +import javax.crypto.Cipher; +import java.security.Key; +import java.security.KeyFactory; +import java.security.spec.X509EncodedKeySpec; +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; + +public class TicketUtil { + /** + * 检查票据格式 + * + * @param ticket + * @return 返回分割后的数组 header + payload + signature + */ + public static String[] checkTicketFormat(String ticket) { + if (ticket == null || ticket.isEmpty()) { + throw new IllegalArgumentException("transform value can't be null or empty!"); + } + String[] strs = ticket.split("\\*"); + if (strs.length != 3) { + throw new IllegalArgumentException("ticket:" + ticket + " is illegal"); + } + return strs; + } + + /** + * 校验票据签名 + * + * @param plainPart header*payload + * @param signature signature + * @param publicKey publicKey + * @return + */ + public static boolean validateTicket(String plainPart, String signature, String publicKey) { + try { + byte[] encryptedData = Base64.getDecoder().decode(signature); + byte[] decryptedData = decryptByPublicKey(Cipher.DECRYPT_MODE, encryptedData, publicKey); + byte[] data = DigestUtils.md5(plainPart); + + if (decryptedData.length != data.length) { + return false; + } + + for (int i = 0; i < data.length; i++) { + if (decryptedData[i] != data[i]) { + return false; + } + } + return true; + } catch (Exception e) { + //log.error("Signature Error", e); + } + return false; + } + + /** + * 将元组格式的字符串转换为字符串数组,例如: + * "(1,1111246415021011037,,,1553777365956)" -> ["1","1111246415021011037", "", "", "1550498840000"].length = 5 + * "(1,(1234567890,suweijie02),1)" -> ["1", "(1234567890,suweijie02)", "1"].length = 3 + * + * @param text + * @return + */ + public static List splitBrackets(String text) { + List list = new ArrayList<>(); + if (text == null || text.isEmpty()) { + return list; + } + if (!text.startsWith("(") || !text.endsWith(")")) { + list.add(text); + return list; + } + int brackets = 0; + StringBuilder sb = new StringBuilder(); + for (int i = 1; i < text.length() - 1; i++) { + char ch = text.charAt(i); + if (ch == ',' && brackets == 0) { + list.add(sb.toString()); + sb = new StringBuilder(); + continue; + } + if (ch == '(') { + brackets++; + } else if (ch == ')') { + brackets--; + } + sb.append(ch); + } + if (brackets != 0) { + throw new IllegalArgumentException("text:" + text + "不符合正确的压缩格式"); + } + if (sb.length() > 0) { + list.add(sb.toString()); + } + return list; + } + + /** + * 公钥解密 + * + * @param mode + * @param data + * @param pubKey + * @return + * @throws Exception + */ + private static byte[] decryptByPublicKey(int mode, byte[] data, String pubKey) throws Exception { + // 对密钥解密 + byte[] keyBytes = Base64.getDecoder().decode(pubKey); + + // 取得公钥 + X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + Key publicKey = keyFactory.generatePublic(x509KeySpec); + + // 对数据加解密 + Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); + cipher.init(mode, publicKey); + + return cipher.doFinal(data); + } + + public static void main(String[] args) throws Exception { + //公钥 + String publicKey = "从接口获取"; + //id-token + String idToken = "(1,1111246415021011037,,,1553777365956)*(1,(2104577,sushiyu),0)*GoOeRQkLurl19UJDdVZk1uoUKlr4hhKCVFYg7tVC9bWuhDmnK6BAwpZuvDDX2/6MF3UrkcRWCdHfmI4WJTD2eg=="; + //检查idToken,并返回分割后的数组 header + payload + signature + String[] strs = checkTicketFormat(idToken); + + //step1 是否过期 + List header = splitBrackets(strs[0]); + long expire = Long.valueOf(header.get(4)); + if (expire < System.currentTimeMillis()) { + throw new Exception("ticket is expire"); + } + + //step 2 验证签名 + if (!validateTicket(strs[0] + "*" + strs[1], strs[2], publicKey)) { + throw new IllegalArgumentException("ticket is illegal"); + } + + //step3 获取用户信息 + List payload = splitBrackets(strs[1]); + List user = splitBrackets(payload.get(1)); + Long uid = Long.parseLong(user.get(0)); + String mis = user.get(1); + } +} + \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/filter/MT1Filter.java b/src/main/java/com/fr/plugin/filter/MT1Filter.java new file mode 100644 index 0000000..8fe9361 --- /dev/null +++ b/src/main/java/com/fr/plugin/filter/MT1Filter.java @@ -0,0 +1,203 @@ +package com.fr.plugin.filter; + +import com.fanruan.api.log.LogKit; +import com.fr.base.ServerConfig; +import com.fr.data.NetworkHelper; +import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider; +import com.fr.decision.mobile.terminal.TerminalHandler; +import com.fr.decision.webservice.v10.login.LoginService; +import com.fr.decision.webservice.v10.login.TokenResource; +import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.MTConfig; +import com.fr.plugin.SsoHttpUtil; +import com.fr.stable.StringUtils; +import com.fr.stable.web.Device; +import com.fr.web.utils.WebUtils; + +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +public class MT1Filter extends AbstractGlobalRequestFilterProvider { + @Override + public String filterName() { + return "MT1Filter"; + } + + @Override + public String[] urlPatterns() { + return new String[]{ + "/*", + }; + } + + @Override + public void init(FilterConfig filterConfig) { + super.init(filterConfig); + //获取一下公钥 + try { + SsoHttpUtil.initPublicKey(); + } catch (Exception e) { + LogKit.error("美团初始化公钥失败", e); + } + } + + @Override + public void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) { + try { + if (isLogOut(req)) { + delLoginOut(req, res); + return; + } + if (needFilter(req) && !isLogin(req)) { + String loginUrl = MTConfig.getInstance().getApiUrl(); + String clientId = MTConfig.getInstance().getClientId(); + String frUrl = MTConfig.getInstance().getFrUrl(); + String originalURL = getUrl(req); + String callback = URLEncoder.encode(frUrl + "url/mtlogin?callback=" + URLEncoder.encode(originalURL, "UTF-8"), "UTF-8"); + String redirectUrl = loginUrl + "/fedauth/authorize?client_id=" + clientId + "&redirect_uri=" + callback; + sendRedirect(res, redirectUrl); + return; + } + + filterChain.doFilter(req, res); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + + private String getUrl(HttpServletRequest request) { + StringBuilder builder=new StringBuilder( ); + + String url = "/"; + try { + url = request.getScheme()+"://" + request.getServerName()//服务器地址 + + ":" + + request.getServerPort() + request.getRequestURI(); + builder.append(url); + Enumeration parameterNames = request.getParameterNames(); + builder.append("?ttt=1"); + while (parameterNames.hasMoreElements()) { + String key = parameterNames.nextElement(); + if(StringUtils.equals(key,"ticket")){ + continue; + } + builder.append("&").append(key).append("=").append(URLEncoder.encode(request.getParameter(key),"UTF-8")); + } + } catch (Exception e) { + e.printStackTrace(); + } + return builder.toString(); + } + private void delLoginOut(HttpServletRequest req, HttpServletResponse res) { + try { + //执行帆软内部的退出 + LoginService.getInstance().logout(req, res); + JSONObject jsonObject = new JSONObject(); + MTConfig mtConfig = MTConfig.getInstance(); + String apiUrl = mtConfig.getApiUrl(); + String clientId = mtConfig.getClientId(); + String callback = URLEncoder.encode(mtConfig.getFrUrl() + "url/mtlogin", "UTF-8"); + String redirectUrl = apiUrl + "/fedauth/authorize?client_id=" + clientId + "&redirect_uri=" + callback; + String logoutUrl = apiUrl + "/sson/logout?client_id=" + clientId + "&redirect_uri=" + URLEncoder.encode(redirectUrl, "UTF-8"); + jsonObject.put("data", logoutUrl); + WebUtils.printAsJSON(res, jsonObject); + } catch (Exception e) { + } + } + + private boolean isLogOut(HttpServletRequest req) { + String url = WebUtils.getOriginalURL(req); + String servletNamePrefix = "/" + ServerConfig.getInstance().getServletName() + "/logout"; + return url.contains(servletNamePrefix) && req.getMethod().equals("POST"); + } + + private void login(HttpServletRequest req, HttpServletResponse res, String username) { + String token = null; + try { + token = LoginService.getInstance().login(req, res, username); + req.setAttribute("fine_auth_token", token); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + FineLoggerFactory.getLogger().error("login failed"); + } + FineLoggerFactory.getLogger().error("login success"); + } + + private boolean isLogin(HttpServletRequest request) { + String oldToken = TokenResource.COOKIE.getToken(request); + return oldToken != null && checkTokenValid(request, (String) oldToken); + } + + private void sendRedirect(HttpServletResponse res, String url) { + res.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); + res.setHeader("Location", url); + } + + private boolean needFilter(HttpServletRequest request) { + String requestURI = request.getRequestURI(); + if (StringUtils.isNotBlank(requestURI) && request.getMethod().equals("GET")) { + if (requestURI.endsWith("decision")||requestURI.endsWith("decision/")) { + return true; + } + if (requestURI.endsWith("/view/form") || requestURI.endsWith("/view/report")) { + if (StringUtils.isNotBlank(request.getParameter("viewlet"))) { + return true; + } + } + if ((requestURI.contains("/v5/api/conf/page") ||requestURI.contains("/v5/api/conf/page/") )&& request.getMethod().equals("GET")) { + return true; + } + if (requestURI.contains("/v10/entry/access/") && request.getMethod().equals("GET")) { + return true; + } + + if (requestURI.contains("/v5/design/report") && (requestURI.endsWith("/edit") || requestURI.endsWith("/view"))) { + return true; + } + if(request.getMethod().equals("GET")){ + for (String filterUrl : filterUrls) { + if (requestURI.endsWith(filterUrl)||requestURI.endsWith(filterUrl+"/")) { + return true; + } + } + } + } + return false; + } + private static List filterUrls=new ArrayList(); + static { + String servletName = ServerConfig.getInstance().getServletName(); + filterUrls.add(servletName+"/dashboard"); + filterUrls.add(servletName+"/dashboard/management"); + filterUrls.add(servletName+"/directory"); + filterUrls.add(servletName+"/user"); + filterUrls.add(servletName+"/dashboard"); + filterUrls.add(servletName+"/privilege"); + filterUrls.add(servletName+"/timer"); + } + private 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; + } + + private static void setCookie(HttpServletResponse response, String name, String value) { + Cookie cookie = new Cookie(name, value); + cookie.setPath("/"); + response.addCookie(cookie); + } + +} diff --git a/src/main/java/com/fr/plugin/http/MTHttpHandler.java b/src/main/java/com/fr/plugin/http/MTHttpHandler.java new file mode 100644 index 0000000..e906460 --- /dev/null +++ b/src/main/java/com/fr/plugin/http/MTHttpHandler.java @@ -0,0 +1,16 @@ +package com.fr.plugin.http; + +import com.fr.decision.fun.HttpHandler; +import com.fr.decision.fun.impl.AbstractHttpHandlerProvider; +import com.fr.plugin.http.handler.*; + +public class MTHttpHandler extends AbstractHttpHandlerProvider { + HttpHandler[] actions = new HttpHandler[]{ + new ALLMtloginCallback1Handler(), + }; + + @Override + public HttpHandler[] registerHandlers() { + return actions; + } +} diff --git a/src/main/java/com/fr/plugin/http/MTUrlAliasProvider.java b/src/main/java/com/fr/plugin/http/MTUrlAliasProvider.java new file mode 100644 index 0000000..6b29609 --- /dev/null +++ b/src/main/java/com/fr/plugin/http/MTUrlAliasProvider.java @@ -0,0 +1,14 @@ +package com.fr.plugin.http; + +import com.fr.decision.fun.impl.AbstractURLAliasProvider; +import com.fr.decision.webservice.url.alias.URLAlias; +import com.fr.decision.webservice.url.alias.URLAliasFactory; + +public class MTUrlAliasProvider extends AbstractURLAliasProvider { + @Override + public URLAlias[] registerAlias() { + return new URLAlias[]{ + URLAliasFactory.createPluginAlias("/mtlogin", "/mtloginCallback", true), + }; + } +} diff --git a/src/main/java/com/fr/plugin/http/handler/ALLMtloginCallback1Handler.java b/src/main/java/com/fr/plugin/http/handler/ALLMtloginCallback1Handler.java new file mode 100644 index 0000000..d3dc4d7 --- /dev/null +++ b/src/main/java/com/fr/plugin/http/handler/ALLMtloginCallback1Handler.java @@ -0,0 +1,126 @@ +package com.fr.plugin.http.handler; + +import com.fanruan.api.log.LogKit; +import com.fanruan.api.net.http.HttpKit; +import com.fr.decision.authority.data.User; +import com.fr.decision.fun.impl.BaseHttpHandler; +import com.fr.decision.webservice.v10.login.LoginService; +import com.fr.decision.webservice.v10.user.UserService; +import com.fr.json.JSONObject; +import com.fr.plugin.MTConfig; +import com.fr.plugin.SsoHttpUtil; +import com.fr.plugin.TicketUtil; +import com.fr.stable.StringUtils; +import com.fr.third.springframework.web.bind.annotation.RequestMethod; +import com.fr.web.utils.WebUtils; +import org.swingexplorer.Log; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ALLMtloginCallback1Handler extends BaseHttpHandler { + @Override + public RequestMethod getMethod() { + return null; + } + + @Override + public String getPath() { + return "/mtloginCallback" ; + } + + @Override + public boolean isPublic() { + return true; + } + + @Override + public void handle(HttpServletRequest req, HttpServletResponse res) throws Exception { + String code = req.getParameter("id-token"); + String url = req.getParameter("callback"); +// String accessToken = getAccessToken(code); +// String userInfo = getUserInfo(accessToken); + String userInfo = loginByTk(code); + UserService userService = UserService.getInstance(); + User user = userService.getUserByUserName(userInfo); + if (user == null) { + String notExistUrl = MTConfig.getInstance().getNotExistUrl(); + sendRedirect(res, notExistUrl); + return; + } + if (!user.isEnable()) { + String notExistUrl = MTConfig.getInstance().getNotExistUrl(); + sendRedirect(res, notExistUrl); + return; + } + login(req,res,userInfo); + LogKit.info("login success, userName=" + userInfo); + if (StringUtils.isBlank(url)) { + url = MTConfig.getInstance().getFrUrl(); + } + sendRedirect(res, url); + } + private void sendRedirect(HttpServletResponse res, String url) { + res.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); + res.setHeader("Location", url); + } + + private void login(HttpServletRequest req, HttpServletResponse res, String username) { + String token = null; + try { + token = LoginService.getInstance().login(req, res, username); + req.setAttribute("fine_auth_token", token); + } catch (Exception e) { + } + } + + private String loginByTk(String idToken) throws Exception { + //检查idToken,并返回分割后的数组 header + payload + signature + LogKit.info("idToken:{}",idToken); + String[] strs = TicketUtil.checkTicketFormat(idToken); + + //step1 是否过期 + List header = TicketUtil.splitBrackets(strs[0]); + long expire = Long.valueOf(header.get(4)); + if (expire < System.currentTimeMillis()) { + throw new Exception("ticket is expire"); + } + + if(StringUtils.isBlank( SsoHttpUtil.getPublicKey())){ + SsoHttpUtil.initPublicKey(); + if(StringUtils.isBlank( SsoHttpUtil.getPublicKey())){ + throw new Exception("public key is null"); + } + } + //step 2 验证签名 + if (!TicketUtil.validateTicket(strs[0] + "*" + strs[1], strs[2], SsoHttpUtil.getPublicKey())) { + throw new IllegalArgumentException("ticket is illegal"); + } + + //step3 获取用户信息 + List payload = TicketUtil.splitBrackets(strs[1]); + List user = TicketUtil.splitBrackets(payload.get(1)); + Long uid = Long.parseLong(user.get(0)); + String mis = user.get(1); + LogKit.info("成功获取:----- uid:{},mis:{}", uid, mis); + return mis; + } + + private String getAccessToken(String code) throws IOException { + MTConfig mtConfig = MTConfig.getInstance(); + String apiUrl = mtConfig.getApiUrl(); + String url = String.format("%s/oauth2.0/access-token", apiUrl); + Map params = new HashMap<>(); + params.put("code", code); + params.put("t", System.currentTimeMillis() + ""); + Map headers = SsoHttpUtil.getSignedHeaders("GET", url, mtConfig.getClientId(), mtConfig.getClientSecret()); + String resp = HttpKit.get(url, params, headers); + LogKit.info("====getAccessToken url:{} params:{} header:{} resp:{}", url, params, headers, resp); + JSONObject entries = new JSONObject(resp); + return entries.getJSONObject("data").getString("accessToken"); + } +}