From 5f20b3fc8ff4818b99289f16924404e2ccc171db Mon Sep 17 00:00:00 2001 From: fit2cloud-chenyw Date: Tue, 14 Sep 2021 18:47:33 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20sso=E5=8D=95=E7=82=B9=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/dataease/auth/entity/TokenInfo.java | 2 +- .../io/dataease/auth/server/AuthServer.java | 10 +-- .../auth/service/impl/ShiroServiceImpl.java | 5 ++ .../java/io/dataease/auth/util/JWTUtils.java | 20 ++++-- .../plugins/server/PluginCommonServer.java | 41 ++++++++++- .../io/dataease/plugins/server/SSOServer.java | 27 ++++++-- .../dataease/plugins/server/XOidcServer.java | 34 ++++++++- frontend/src/views/login/index.vue | 6 ++ .../src/views/system/plugin/PluginCom.vue | 69 +++++++++++++++++++ frontend/src/views/system/user/index.vue | 2 +- 10 files changed, 193 insertions(+), 23 deletions(-) create mode 100644 frontend/src/views/system/plugin/PluginCom.vue diff --git a/backend/src/main/java/io/dataease/auth/entity/TokenInfo.java b/backend/src/main/java/io/dataease/auth/entity/TokenInfo.java index 3811afd603..e018cca48a 100644 --- a/backend/src/main/java/io/dataease/auth/entity/TokenInfo.java +++ b/backend/src/main/java/io/dataease/auth/entity/TokenInfo.java @@ -13,7 +13,7 @@ public class TokenInfo implements Serializable { private Long userId; - private String idToken; + /* private String idToken; */ public String format(){ return username + "," +userId; diff --git a/backend/src/main/java/io/dataease/auth/server/AuthServer.java b/backend/src/main/java/io/dataease/auth/server/AuthServer.java index b0e5dc9de9..03925bb8b8 100644 --- a/backend/src/main/java/io/dataease/auth/server/AuthServer.java +++ b/backend/src/main/java/io/dataease/auth/server/AuthServer.java @@ -22,18 +22,18 @@ import io.dataease.plugins.xpack.ldap.dto.request.LdapValidateRequest; import io.dataease.plugins.xpack.ldap.dto.response.ValidateResult; import io.dataease.plugins.xpack.ldap.service.LdapXpackService; import io.dataease.plugins.xpack.oidc.service.OidcXpackService; - import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.SecurityUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; - import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.servlet.http.HttpServletRequest; + @RestController public class AuthServer implements AuthApi { @@ -115,13 +115,13 @@ public class AuthServer implements AuthApi { @Override public String logout() { String token = ServletUtils.getToken(); + if (isOpenOidc()) { + HttpServletRequest request = ServletUtils.request(); + String idToken = request.getHeader("IdToken"); OidcXpackService oidcXpackService = SpringContextUtil.getBean(OidcXpackService.class); - TokenInfo tokenInfo = JWTUtils.tokenInfoByToken(token); - String idToken = tokenInfo.getIdToken(); oidcXpackService.logout(idToken); } - // String token = ServletUtils.getToken(); if (StringUtils.isEmpty(token) || StringUtils.equals("null", token) || StringUtils.equals("undefined", token)) { return "success"; } diff --git a/backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java b/backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java index bc083f02ec..aecb307469 100644 --- a/backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java +++ b/backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java @@ -60,6 +60,11 @@ public class ShiroServiceImpl implements ShiroService { filterChainDefinitionMap.put("/api/auth/validateName", ANON); filterChainDefinitionMap.put("/api/auth/isOpenLdap", ANON); filterChainDefinitionMap.put("/api/auth/isOpenOidc", ANON); + filterChainDefinitionMap.put("/api/pluginCommon/component/*", ANON); + filterChainDefinitionMap.put("/plugin/oidc/authInfo", ANON); + filterChainDefinitionMap.put("/sso/callBack*", ANON); + + filterChainDefinitionMap.put("/unauth", ANON); filterChainDefinitionMap.put("/display/**", ANON); filterChainDefinitionMap.put("/tokenExpired", ANON); diff --git a/backend/src/main/java/io/dataease/auth/util/JWTUtils.java b/backend/src/main/java/io/dataease/auth/util/JWTUtils.java index c32b956999..544c7a9cb8 100644 --- a/backend/src/main/java/io/dataease/auth/util/JWTUtils.java +++ b/backend/src/main/java/io/dataease/auth/util/JWTUtils.java @@ -8,6 +8,7 @@ import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.Verification; import io.dataease.auth.entity.TokenInfo; +import io.dataease.auth.entity.TokenInfo.TokenInfoBuilder; import io.dataease.commons.utils.CommonBeanFactory; import io.dataease.exception.DataEaseException; import org.apache.commons.lang3.ObjectUtils; @@ -38,9 +39,9 @@ public class JWTUtils { Verification verification = JWT.require(algorithm) .withClaim("username", tokenInfo.getUsername()) .withClaim("userId", tokenInfo.getUserId()); - if (StringUtils.isNotBlank(tokenInfo.getIdToken())) { + /* if (StringUtils.isNotBlank(tokenInfo.getIdToken())) { verification.withClaim("idToken", tokenInfo.getIdToken()); - } + } */ JWTVerifier verifier = verification.build(); verifier.verify(token); return true; @@ -54,10 +55,15 @@ public class JWTUtils { DecodedJWT jwt = JWT.decode(token); String username = jwt.getClaim("username").asString(); Long userId = jwt.getClaim("userId").asLong(); + // String idToken = jwt.getClaim("idToken").asString(); if (StringUtils.isEmpty(username) || ObjectUtils.isEmpty(userId) ){ DataEaseException.throwException("token格式错误!"); } - TokenInfo tokenInfo = TokenInfo.builder().username(username).userId(userId).build(); + TokenInfoBuilder tokenInfoBuilder = TokenInfo.builder().username(username).userId(userId); + /* if (StringUtils.isNotBlank(idToken)) { + tokenInfoBuilder.idToken(idToken); + } */ + TokenInfo tokenInfo = tokenInfoBuilder.build(); return tokenInfo; } @@ -114,11 +120,11 @@ public class JWTUtils { Builder builder = JWT.create() .withClaim("username", tokenInfo.getUsername()) .withClaim("userId", tokenInfo.getUserId()); - if (StringUtils.isNotBlank(tokenInfo.getIdToken())) { + /* if (StringUtils.isNotBlank(tokenInfo.getIdToken())) { builder.withClaim("idToken", tokenInfo.getIdToken()); - } - return builder.withExpiresAt(date) - .sign(algorithm); + } */ + return builder.withExpiresAt(date).sign(algorithm); + } catch (Exception e) { return null; } diff --git a/backend/src/main/java/io/dataease/plugins/server/PluginCommonServer.java b/backend/src/main/java/io/dataease/plugins/server/PluginCommonServer.java index 225542842f..b33e60244c 100644 --- a/backend/src/main/java/io/dataease/plugins/server/PluginCommonServer.java +++ b/backend/src/main/java/io/dataease/plugins/server/PluginCommonServer.java @@ -2,6 +2,7 @@ package io.dataease.plugins.server; import io.dataease.commons.utils.ServletUtils; import io.dataease.plugins.common.dto.PluginSysMenu; +import io.dataease.plugins.common.service.PluginComponentService; import io.dataease.plugins.common.service.PluginMenuService; import io.dataease.plugins.config.SpringContextUtil; import org.springframework.web.bind.annotation.GetMapping; @@ -9,7 +10,6 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import springfox.documentation.annotations.ApiIgnore; - import javax.servlet.http.HttpServletResponse; import java.io.BufferedInputStream; import java.io.IOException; @@ -25,7 +25,7 @@ import java.util.concurrent.atomic.AtomicReference; public class PluginCommonServer { @GetMapping("/async/{menuId}") - public void componentInfo(@PathVariable Long menuId) { + public void menuInfo(@PathVariable Long menuId) { Map pluginMenuServiceMap = SpringContextUtil.getApplicationContext().getBeansOfType(PluginMenuService.class); pluginMenuServiceMap.values().stream().forEach(service -> { AtomicReference atomicReference = new AtomicReference<>(); @@ -65,4 +65,41 @@ public class PluginCommonServer { return; }); } + + @GetMapping("/component/{componentName}") + public void componentInfo(@PathVariable String componentName) { + Map beansOfType = SpringContextUtil.getApplicationContext().getBeansOfType(PluginComponentService.class); + beansOfType.values().stream().forEach(service -> { + List components = service.components(); + if (components.contains(componentName)) { + HttpServletResponse response = ServletUtils.response(); + BufferedInputStream bis = null; + InputStream inputStream = null; + OutputStream os = null; //输出流 + try{ + inputStream = service.vueResource(componentName); + byte[] buffer = new byte[1024]; + os = response.getOutputStream(); + bis = new BufferedInputStream(inputStream); + int i = bis.read(buffer); + while(i != -1){ + os.write(buffer, 0, i); + i = bis.read(buffer); + } + os.flush(); + }catch (Exception e) { + e.printStackTrace(); + }finally { + try { + bis.close(); + inputStream.close(); + os.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return; + } + }); + } } diff --git a/backend/src/main/java/io/dataease/plugins/server/SSOServer.java b/backend/src/main/java/io/dataease/plugins/server/SSOServer.java index 1e82ae0ed1..d91d48df62 100644 --- a/backend/src/main/java/io/dataease/plugins/server/SSOServer.java +++ b/backend/src/main/java/io/dataease/plugins/server/SSOServer.java @@ -3,6 +3,10 @@ package io.dataease.plugins.server; import java.util.List; import java.util.Map; import java.util.stream.Collectors; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @@ -14,6 +18,7 @@ import io.dataease.auth.entity.TokenInfo; import io.dataease.auth.service.AuthUserService; import io.dataease.auth.util.JWTUtils; import io.dataease.commons.exception.DEException; +import io.dataease.commons.utils.CodingUtil; import io.dataease.commons.utils.ServletUtils; import io.dataease.plugins.config.SpringContextUtil; import io.dataease.plugins.xpack.display.dto.response.SysSettingDto; @@ -33,8 +38,7 @@ public class SSOServer { private SysUserService sysUserService; @GetMapping("/callBack") - public ModelAndView callBack(@RequestParam("code") String code, @RequestParam("statue") String state) { - + public ModelAndView callBack(@RequestParam("code") String code, @RequestParam("state") String state) { Map beansOfType = SpringContextUtil.getApplicationContext().getBeansOfType((OidcXpackService.class)); if(beansOfType.keySet().size() == 0) { DEException.throwException("缺少oidc插件"); @@ -44,18 +48,29 @@ public class SSOServer { if (!suuportOIDC) { DEException.throwException("未开启oidc"); } - SSOToken ssoToken = oidcXpackService.requestSsoToken(code, state); Map config = config(oidcXpackService); + SSOToken ssoToken = oidcXpackService.requestSsoToken(config, code, state); + SSOUserInfo ssoUserInfo = oidcXpackService.requestUserInfo(config, ssoToken.getAccessToken()); SysUserEntity sysUserEntity = authUserService.getUserByName(ssoUserInfo.getUserName()); if(null == sysUserEntity){ sysUserService.saveOIDCUser(ssoUserInfo); sysUserEntity = authUserService.getUserByName(ssoUserInfo.getUserName()); } - TokenInfo tokenInfo = TokenInfo.builder().userId(sysUserEntity.getUserId()).username(sysUserEntity.getUsername()).idToken(ssoToken.getIdToken()).build(); - String token = JWTUtils.sign(tokenInfo, sysUserService.defaultPWD()); + TokenInfo tokenInfo = TokenInfo.builder().userId(sysUserEntity.getUserId()).username(sysUserEntity.getUsername()).build(); + String realPwd = CodingUtil.md5(sysUserService.defaultPWD()); + String token = JWTUtils.sign(tokenInfo, realPwd); ServletUtils.setToken(token); - ModelAndView modelAndView = new ModelAndView("/"); + HttpServletResponse response = ServletUtils.response(); + + Cookie cookie_token = new Cookie("Authorization", token);cookie_token.setPath("/"); + Cookie cookie_id_token = new Cookie("IdToken", ssoToken.getIdToken());cookie_id_token.setPath("/"); + Cookie cookie_ac_token = new Cookie("AccessToken", ssoToken.getAccessToken());cookie_ac_token.setPath("/"); + + response.addCookie(cookie_token); + response.addCookie(cookie_id_token); + response.addCookie(cookie_ac_token); + ModelAndView modelAndView = new ModelAndView("redirect:/"); return modelAndView; } private Map config(OidcXpackService oidcXpackService) { diff --git a/backend/src/main/java/io/dataease/plugins/server/XOidcServer.java b/backend/src/main/java/io/dataease/plugins/server/XOidcServer.java index c2c21f24e7..debb306ccc 100644 --- a/backend/src/main/java/io/dataease/plugins/server/XOidcServer.java +++ b/backend/src/main/java/io/dataease/plugins/server/XOidcServer.java @@ -4,9 +4,11 @@ package io.dataease.plugins.server; import io.dataease.plugins.config.SpringContextUtil; import io.dataease.plugins.xpack.display.dto.response.SysSettingDto; import io.dataease.plugins.xpack.oidc.service.OidcXpackService; +import org.apache.commons.lang3.StringUtils; import org.springframework.web.bind.annotation.*; - +import java.util.HashMap; import java.util.List; +import java.util.Map; @RequestMapping("/plugin/oidc") @RestController @@ -24,4 +26,34 @@ public class XOidcServer { OidcXpackService oidcXpackService = SpringContextUtil.getBean(OidcXpackService.class); oidcXpackService.save(settings); } + + @PostMapping(value="/authInfo") + public Map authInfo() { + OidcXpackService oidcXpackService = SpringContextUtil.getBean(OidcXpackService.class); + Map result = new HashMap(); + List oidcSettings = oidcXpackService.oidcSettings(); + + Map authParam = new HashMap<>(); + authParam.put("response_type", "code"); + authParam.put("state", "state"); + // authParam.put("redirect_uri", "http://localhost:9528"); + + + oidcSettings.forEach(param -> { + if(StringUtils.isNotBlank(param.getParamKey())) { + if (StringUtils.equals(param.getParamKey(), "oidc.authEndpoint")) { + result.put("authEndpoint", param.getParamValue()); + } + if (StringUtils.equals(param.getParamKey(), "oidc.scope")) { + authParam.put("scope", param.getParamValue()); + } + if (StringUtils.equals(param.getParamKey(), "oidc.clientId")) { + authParam.put("client_id", param.getParamValue()); + } + } + + }); + result.put("authParam", authParam); + return result; + } } diff --git a/frontend/src/views/login/index.vue b/frontend/src/views/login/index.vue index a5ad1e987d..552452644a 100644 --- a/frontend/src/views/login/index.vue +++ b/frontend/src/views/login/index.vue @@ -56,6 +56,7 @@ + @@ -64,8 +65,10 @@ import { encrypt } from '@/utils/rsaEncrypt' import { ldapStatus, oidcStatus } from '@/api/user' import { getSysUI } from '@/utils/auth' +import PluginCom from '@/views/system/plugin/PluginCom' export default { name: 'Login', + components: { PluginCom }, data() { return { loginForm: { @@ -156,6 +159,9 @@ export default { }, changeLoginType(val) { if (val !== 2) return + this.$nextTick(() => { + + }) } } } diff --git a/frontend/src/views/system/plugin/PluginCom.vue b/frontend/src/views/system/plugin/PluginCom.vue new file mode 100644 index 0000000000..53ba11cba1 --- /dev/null +++ b/frontend/src/views/system/plugin/PluginCom.vue @@ -0,0 +1,69 @@ + + + diff --git a/frontend/src/views/system/user/index.vue b/frontend/src/views/system/user/index.vue index c5f4188913..1a9d8555f9 100644 --- a/frontend/src/views/system/user/index.vue +++ b/frontend/src/views/system/user/index.vue @@ -22,7 +22,7 @@