From 364be22dd080974aa9fc7e148e03069f2fc83faa Mon Sep 17 00:00:00 2001 From: EightMonth Date: Fri, 8 Mar 2024 16:30:23 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9Etoken=E6=A0=A1=E9=AA=8C?= =?UTF-8?q?=E3=80=81=E5=AE=A2=E6=88=B7=E7=AB=AF=E4=BE=BF=E6=8D=B7=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E7=B1=BB=E3=80=81=E4=BF=AE=E5=A4=8D=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E7=BC=BA=E4=B9=8F=E7=A7=9F=E6=88=B7=E4=BF=A1=E6=81=AF=E3=80=81?= =?UTF-8?q?=E5=BC=BA=E9=80=80=E5=8A=9F=E8=83=BD=E5=A4=B1=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/jeecg/common/api/CommonAPI.java | 8 ++ .../jeecg/common/constant/CommonConstant.java | 2 +- .../org/jeecg/common/system/util/JwtUtil.java | 28 ++++-- .../jeecg/config/security/ClientService.java | 90 +++++++++++++++++++ .../security/JeecgPermissionService.java | 1 + ...edisOAuth2AuthorizationConsentService.java | 3 + .../JeecgRedisOAuth2AuthorizationService.java | 1 + .../security/RedisTokenValidationFilter.java | 49 ++++++++++ .../jeecg/config/security/SecurityConfig.java | 5 +- .../app/AppGrantAuthenticationConvert.java | 1 + .../app/AppGrantAuthenticationProvider.java | 14 ++- .../app/AppGrantAuthenticationToken.java | 1 + .../PasswordGrantAuthenticationConvert.java | 1 + .../PasswordGrantAuthenticationProvider.java | 14 ++- .../PasswordGrantAuthenticationToken.java | 1 + .../PhoneGrantAuthenticationConvert.java | 1 + .../PhoneGrantAuthenticationProvider.java | 12 ++- .../phone/PhoneGrantAuthenticationToken.java | 1 + .../SocialGrantAuthenticationConvert.java | 1 + .../SocialGrantAuthenticationProvider.java | 12 ++- .../SocialGrantAuthenticationToken.java | 1 + .../config/security/utils/SecureUtil.java | 6 ++ .../jeecg/common/system/api/ISysBaseAPI.java | 2 + .../api/fallback/SysBaseAPIFallback.java | 5 ++ .../api/controller/SystemApiController.java | 5 ++ .../system/service/impl/SysBaseApiImpl.java | 8 ++ 26 files changed, 260 insertions(+), 13 deletions(-) create mode 100644 jeecg-boot-base-core/src/main/java/org/jeecg/config/security/ClientService.java create mode 100644 jeecg-boot-base-core/src/main/java/org/jeecg/config/security/RedisTokenValidationFilter.java diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/CommonAPI.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/CommonAPI.java index 79b60305..aa3e483b 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/CommonAPI.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/CommonAPI.java @@ -1,5 +1,6 @@ package org.jeecg.common.api; +import com.alibaba.fastjson.JSONObject; import org.jeecg.common.system.vo.*; import java.util.List; @@ -154,4 +155,11 @@ public interface CommonAPI { */ void updateUserDepart(String username,String orgCode,Integer loginTenantId); + /** + * 设置登录租户 + * @param username + * @return + */ + JSONObject setLoginTenant(String username); + } diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java index 57442a7e..c84038e6 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java @@ -78,7 +78,7 @@ public interface CommonConstant { /** 登录用户Shiro权限缓存KEY前缀 */ public static String PREFIX_USER_SHIRO_CACHE = "shiro:cache:org.jeecg.config.shiro.ShiroRealm.authorizationCache:"; /** 登录用户Token令牌缓存KEY前缀 */ - String PREFIX_USER_TOKEN = "prefix_user_token:"; + String PREFIX_USER_TOKEN = "token::jeecg-client::"; // /** Token缓存时间:3600秒即一小时 */ // int TOKEN_EXPIRE_TIME = 3600; diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/JwtUtil.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/JwtUtil.java index da97d957..6958e855 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/JwtUtil.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/JwtUtil.java @@ -12,13 +12,20 @@ import com.google.common.base.Joiner; import java.io.IOException; import java.io.OutputStream; +import java.util.ArrayList; import java.util.Date; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; import lombok.extern.slf4j.Slf4j; +import org.jeecg.common.api.CommonAPI; import org.jeecg.common.api.vo.Result; import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.constant.DataBaseConstant; @@ -31,7 +38,17 @@ import org.jeecg.common.util.DateUtils; import org.jeecg.common.util.SpringContextUtils; import org.jeecg.common.util.oConvertUtils; import org.jeecg.config.security.utils.SecureUtil; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.core.*; +import org.springframework.security.oauth2.jwt.JwtDecoder; +import org.springframework.security.oauth2.server.authorization.OAuth2TokenType; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; +import org.springframework.security.oauth2.server.authorization.context.AuthorizationServerContextHolder; +import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext; +import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext; +import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator; /** * @Author Scott @@ -45,6 +62,8 @@ public class JwtUtil { public static final long EXPIRE_TIME = (7 * 12) * 60 * 60 * 1000; static final String WELL_NUMBER = SymbolConstant.WELL_NUMBER + SymbolConstant.LEFT_CURLY_BRACKET; + public static final String DEFAULT_CLIENT = "jeecg-client"; + /** * * @param response @@ -80,10 +99,9 @@ public class JwtUtil { public static boolean verify(String token, String username, String secret) { try { // 根据密码生成JWT效验器 - Algorithm algorithm = Algorithm.HMAC256(secret); - JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build(); + JwtDecoder jwtDecoder = SpringContextUtils.getBean(JwtDecoder.class); // 效验TOKEN - DecodedJWT jwt = verifier.verify(token); + jwtDecoder.decode(token); return true; } catch (Exception exception) { return false; @@ -98,7 +116,7 @@ public class JwtUtil { public static String getUsername(String token) { try { DecodedJWT jwt = JWT.decode(token); - LoginUser loginUser = SecureUtil.currentUser(); + LoginUser loginUser = JSONObject.parseObject(jwt.getClaim("sub").asString(), LoginUser.class); return loginUser.getUsername(); } catch (JWTDecodeException e) { return null; @@ -106,7 +124,7 @@ public class JwtUtil { } /** - * 生成签名,5min后过期 + * 生成签名,5min后过期(暂未实现) * * @param username 用户名 * @param secret 用户的密码 diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/ClientService.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/ClientService.java new file mode 100644 index 00000000..c1318998 --- /dev/null +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/ClientService.java @@ -0,0 +1,90 @@ +package org.jeecg.config.security; + +import lombok.AllArgsConstructor; +import org.springframework.security.oauth2.core.AuthorizationGrantType; +import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; +import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat; +import org.springframework.security.oauth2.server.authorization.settings.TokenSettings; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.util.Set; + +/** + * spring authorization server 注册客户端便捷工具类 + * @author eightmonth@qq.com + * @date 2024/3/7 11:22 + */ +@Component +@AllArgsConstructor +public class ClientService { + + private RegisteredClientRepository registeredClientRepository; + + /** + * 修改客户端token有效期 + * 认证码、设备码有效期与accessToken有效期保持一致 + */ + public void updateTokenValidation(String clientId, Long accessTokenValidation, Long refreshTokenValidation){ + RegisteredClient registeredClient = findByClientId(clientId); + RegisteredClient.Builder builder = RegisteredClient.from(registeredClient); + TokenSettings tokenSettings = TokenSettings.builder() + .idTokenSignatureAlgorithm(SignatureAlgorithm.RS256) + .accessTokenTimeToLive(Duration.ofSeconds(accessTokenValidation)) + .accessTokenFormat(OAuth2TokenFormat.SELF_CONTAINED) + .reuseRefreshTokens(true) + .refreshTokenTimeToLive(Duration.ofSeconds(refreshTokenValidation)) + .authorizationCodeTimeToLive(Duration.ofSeconds(accessTokenValidation)) + .deviceCodeTimeToLive(Duration.ofSeconds(accessTokenValidation)) + .build(); + builder.tokenSettings(tokenSettings); + registeredClientRepository.save(builder.build()); + } + + /** + * 修改客户端授权类型 + * @param clientId + * @param grantTypes + */ + public void updateGrantType(String clientId, Set grantTypes) { + RegisteredClient registeredClient = findByClientId(clientId); + RegisteredClient.Builder builder = RegisteredClient.from(registeredClient); + for (AuthorizationGrantType grantType : grantTypes) { + builder.authorizationGrantType(grantType); + } + registeredClientRepository.save(builder.build()); + } + + /** + * 修改客户端重定向uri + * @param clientId + * @param redirectUris + */ + public void updateRedirectUris(String clientId, String redirectUris) { + RegisteredClient registeredClient = findByClientId(clientId); + RegisteredClient.Builder builder = RegisteredClient.from(registeredClient); + builder.redirectUri(redirectUris); + registeredClientRepository.save(builder.build()); + } + + /** + * 修改客户端授权范围 + * @param clientId + * @param scopes + */ + public void updateScopes(String clientId, Set scopes) { + RegisteredClient registeredClient = findByClientId(clientId); + RegisteredClient.Builder builder = RegisteredClient.from(registeredClient); + for (String scope : scopes) { + builder.scope(scope); + } + registeredClientRepository.save(builder.build()); + } + + public RegisteredClient findByClientId(String clientId) { + return registeredClientRepository.findByClientId(clientId); + } + +} diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/JeecgPermissionService.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/JeecgPermissionService.java index 69e10253..fdb4a915 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/JeecgPermissionService.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/JeecgPermissionService.java @@ -12,6 +12,7 @@ import org.springframework.util.StringUtils; import java.util.Set; /** + * spring authorization server自定义权限处理,根据@PreAuthorize注解,判断当前用户是否具备权限 * @author EightMonth * @date 2024/1/10 17:00 */ diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/JeecgRedisOAuth2AuthorizationConsentService.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/JeecgRedisOAuth2AuthorizationConsentService.java index 5ca2113a..5efb246a 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/JeecgRedisOAuth2AuthorizationConsentService.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/JeecgRedisOAuth2AuthorizationConsentService.java @@ -9,6 +9,9 @@ import org.springframework.util.Assert; import java.util.concurrent.TimeUnit; +/** + * spring authorization server 自定义redis保存授权范围信息 + */ @Component @RequiredArgsConstructor public class JeecgRedisOAuth2AuthorizationConsentService implements OAuth2AuthorizationConsentService { diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/JeecgRedisOAuth2AuthorizationService.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/JeecgRedisOAuth2AuthorizationService.java index cdbb7dc5..d46ab3ce 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/JeecgRedisOAuth2AuthorizationService.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/JeecgRedisOAuth2AuthorizationService.java @@ -24,6 +24,7 @@ import java.util.Set; import java.util.concurrent.TimeUnit; /** + * spring authorization server自定义redis保存认证信息 * @author EightMonth */ @Component diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/RedisTokenValidationFilter.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/RedisTokenValidationFilter.java new file mode 100644 index 00000000..96daa9f2 --- /dev/null +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/RedisTokenValidationFilter.java @@ -0,0 +1,49 @@ +package org.jeecg.config.security; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.AllArgsConstructor; +import org.jeecg.common.system.util.JwtUtil; +import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.jwt.JwtDecoder; +import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; +import org.springframework.security.oauth2.server.authorization.OAuth2TokenType; +import org.springframework.security.oauth2.server.resource.BearerTokenErrors; +import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; +import java.util.Objects; + +/** + * 当用户被强退时,使客户端token失效 + * @author eightmonth@qq.com + * @date 2024/3/7 17:30 + */ +@Component +@AllArgsConstructor +public class RedisTokenValidationFilter extends OncePerRequestFilter { + private OAuth2AuthorizationService authorizationService; + private JwtDecoder jwtDecoder; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + // 从请求中获取token + DefaultBearerTokenResolver defaultBearerTokenResolver = new DefaultBearerTokenResolver(); + String token = defaultBearerTokenResolver.resolve(request); + + + if (Objects.nonNull(token)) { + // 检查认证信息是否已被清除,如果已被清除,则令该token失效 + OAuth2Authorization oAuth2Authorization = authorizationService.findByToken(token, OAuth2TokenType.ACCESS_TOKEN); + if (Objects.isNull(oAuth2Authorization)) { + throw new OAuth2AuthenticationException(BearerTokenErrors.invalidToken("认证信息已失效,请重新登录")); + } + } + filterChain.doFilter(request, response); + } +} diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/SecurityConfig.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/SecurityConfig.java index 7f22a93e..f4dd531d 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/SecurityConfig.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/SecurityConfig.java @@ -37,6 +37,7 @@ import org.springframework.security.oauth2.server.authorization.settings.Authori import org.springframework.security.oauth2.server.authorization.token.*; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher; import org.springframework.web.cors.CorsConfiguration; @@ -49,6 +50,7 @@ import java.util.Arrays; import java.util.UUID; /** + * spring authorization server核心配置 * @author eightmonth@qq.com * @date 2024/1/2 9:29 */ @@ -66,6 +68,7 @@ public class SecurityConfig { public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception { OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http); + // 注册自定义登录类型 http.getConfigurer(OAuth2AuthorizationServerConfigurer.class) .tokenEndpoint(tokenEndpoint -> tokenEndpoint.accessTokenRequestConverter(new PasswordGrantAuthenticationConvert()) .authenticationProvider(new PasswordGrantAuthenticationProvider(authorizationService, tokenGenerator()))) @@ -172,7 +175,7 @@ public class SecurityConfig { } /** - * 注册客户端信息 + * 数据库保存注册客户端信息 */ @Bean public RegisteredClientRepository registeredClientRepository() { diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/app/AppGrantAuthenticationConvert.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/app/AppGrantAuthenticationConvert.java index 588f8fd8..2f081702 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/app/AppGrantAuthenticationConvert.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/app/AppGrantAuthenticationConvert.java @@ -16,6 +16,7 @@ import java.util.HashMap; import java.util.Map; /** + * APP模式认证转换器 * @author EightMonth * @date 2024/1/1 */ diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/app/AppGrantAuthenticationProvider.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/app/AppGrantAuthenticationProvider.java index 2d403401..837deeef 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/app/AppGrantAuthenticationProvider.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/app/AppGrantAuthenticationProvider.java @@ -1,5 +1,6 @@ package org.jeecg.config.security.app; +import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.jeecg.common.api.CommonAPI; import org.jeecg.common.constant.CommonConstant; @@ -40,6 +41,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; /** + * APP模式认证处理器,负责处理该认证模式下的核心逻辑 * @author EightMonth * @date 2024/1/1 */ @@ -85,7 +87,7 @@ public class AppGrantAuthenticationProvider implements AuthenticationProvider { String captcha = (String) additionalParameter.get("captcha"); String checkKey = (String) additionalParameter.get("checkKey"); - + // 检查登录失败次数 if(isLoginFailOvertimes(username)){ throw new JeecgBootException("该用户登录失败次数过多,请于10分钟后再次登录!"); } @@ -112,6 +114,7 @@ public class AppGrantAuthenticationProvider implements AuthenticationProvider { throw new JeecgBootException("非法登录"); } + // 通过用户名获取用户信息 LoginUser loginUser = commonAPI.getUserByName(username); // 检查用户可行性 checkUserIsEffective(loginUser); @@ -180,6 +183,7 @@ public class AppGrantAuthenticationProvider implements AuthenticationProvider { OAuth2Authorization authorization = authorizationBuilder.build(); + // 保存认证信息至redis authorizationService.save(authorization); // 登录成功,删除redis中的验证码 @@ -187,7 +191,12 @@ public class AppGrantAuthenticationProvider implements AuthenticationProvider { redisUtil.del(CommonConstant.LOGIN_FAIL + username); baseCommonService.addLog("用户名: " + username + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser); - Map addition = new HashMap<>(); + JSONObject addition = new JSONObject(new LinkedHashMap<>()); + + // 设置租户 + JSONObject jsonObject = commonAPI.setLoginTenant(username); + addition.putAll(jsonObject.getInnerMap()); + // 设置登录用户信息 addition.put("userInfo", loginUser); addition.put("sysAllDictItems", commonAPI.queryAllDictItems()); @@ -207,6 +216,7 @@ public class AppGrantAuthenticationProvider implements AuthenticationProvider { addition.put("multi_depart", 2); } + // 返回access_token、refresh_token以及其它信息给到前端 return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, addition); } diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/app/AppGrantAuthenticationToken.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/app/AppGrantAuthenticationToken.java index 619f028c..4ed2a280 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/app/AppGrantAuthenticationToken.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/app/AppGrantAuthenticationToken.java @@ -8,6 +8,7 @@ import org.springframework.security.oauth2.server.authorization.authentication.O import java.util.Map; /** + * APP模式认证专用token类型,方法spring authorization server进行认证流转,配合convert使用 * @author EightMonth * @date 2024/1/1 */ diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/password/PasswordGrantAuthenticationConvert.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/password/PasswordGrantAuthenticationConvert.java index 9d0d5c44..083c4bc8 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/password/PasswordGrantAuthenticationConvert.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/password/PasswordGrantAuthenticationConvert.java @@ -17,6 +17,7 @@ import java.util.HashMap; import java.util.Map; /** + * 密码模式认证转换器 * @author EightMonth * @date 2024/1/1 */ diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/password/PasswordGrantAuthenticationProvider.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/password/PasswordGrantAuthenticationProvider.java index c04a774a..7452a9d4 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/password/PasswordGrantAuthenticationProvider.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/password/PasswordGrantAuthenticationProvider.java @@ -1,5 +1,6 @@ package org.jeecg.config.security.password; +import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.jeecg.common.api.CommonAPI; import org.jeecg.common.constant.CommonConstant; @@ -41,6 +42,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; /** + * 密码模式认证处理器,负责处理该认证模式下的核心逻辑 * @author EightMonth * @date 2024/1/1 */ @@ -86,7 +88,7 @@ public class PasswordGrantAuthenticationProvider implements AuthenticationProvid String captcha = (String) additionalParameter.get("captcha"); String checkKey = (String) additionalParameter.get("checkKey"); - + // 检查登录失败次数 if(isLoginFailOvertimes(username)){ throw new JeecgBootException("该用户登录失败次数过多,请于10分钟后再次登录!"); } @@ -113,6 +115,7 @@ public class PasswordGrantAuthenticationProvider implements AuthenticationProvid throw new JeecgBootException("非法登录"); } + // 通过用户名获取用户信息 LoginUser loginUser = commonAPI.getUserByName(username); // 检查用户可行性 checkUserIsEffective(loginUser); @@ -181,6 +184,7 @@ public class PasswordGrantAuthenticationProvider implements AuthenticationProvid OAuth2Authorization authorization = authorizationBuilder.build(); + // 保存认证信息至redis authorizationService.save(authorization); // 登录成功,删除redis中的验证码 @@ -188,7 +192,12 @@ public class PasswordGrantAuthenticationProvider implements AuthenticationProvid redisUtil.del(CommonConstant.LOGIN_FAIL + username); baseCommonService.addLog("用户名: " + username + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser); - Map addition = new HashMap<>(); + JSONObject addition = new JSONObject(new LinkedHashMap<>()); + + // 设置租户 + JSONObject jsonObject = commonAPI.setLoginTenant(username); + addition.putAll(jsonObject.getInnerMap()); + // 设置登录用户信息 addition.put("userInfo", loginUser); addition.put("sysAllDictItems", commonAPI.queryAllDictItems()); @@ -208,6 +217,7 @@ public class PasswordGrantAuthenticationProvider implements AuthenticationProvid addition.put("multi_depart", 2); } + // 返回access_token、refresh_token以及其它信息给到前端 return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, addition); } diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/password/PasswordGrantAuthenticationToken.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/password/PasswordGrantAuthenticationToken.java index 0528167d..32d35cfd 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/password/PasswordGrantAuthenticationToken.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/password/PasswordGrantAuthenticationToken.java @@ -8,6 +8,7 @@ import org.springframework.security.oauth2.server.authorization.authentication.O import java.util.Map; /** + * 密码模式认证专用token类型,方法spring authorization server进行认证流转,配合convert使用 * @author EightMonth * @date 2024/1/1 */ diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/phone/PhoneGrantAuthenticationConvert.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/phone/PhoneGrantAuthenticationConvert.java index 66d92927..0c2d2ee2 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/phone/PhoneGrantAuthenticationConvert.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/phone/PhoneGrantAuthenticationConvert.java @@ -16,6 +16,7 @@ import java.util.HashMap; import java.util.Map; /** + * 手机号模式认证转换器 * @author EightMonth * @date 2024/1/1 */ diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/phone/PhoneGrantAuthenticationProvider.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/phone/PhoneGrantAuthenticationProvider.java index 08cd27f1..d369cb7a 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/phone/PhoneGrantAuthenticationProvider.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/phone/PhoneGrantAuthenticationProvider.java @@ -1,5 +1,6 @@ package org.jeecg.config.security.phone; +import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.jeecg.common.api.CommonAPI; import org.jeecg.common.constant.CommonConstant; @@ -40,6 +41,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; /** + * 手机号模式认证处理器,负责处理该认证模式下的核心逻辑 * @author EightMonth * @date 2024/1/1 */ @@ -87,6 +89,7 @@ public class PhoneGrantAuthenticationProvider implements AuthenticationProvider // 验证码 String captcha = (String) additionalParameter.get("captcha"); + // 通过手机号获取用户信息 LoginUser loginUser = commonAPI.getUserByPhone(phone); // 检查用户可行性 checkUserIsEffective(loginUser); @@ -166,11 +169,17 @@ public class PhoneGrantAuthenticationProvider implements AuthenticationProvider OAuth2Authorization authorization = authorizationBuilder.build(); + // 保存认证信息至redis authorizationService.save(authorization); baseCommonService.addLog("用户名: " + loginUser.getUsername() + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser); - Map addition = new HashMap<>(); + JSONObject addition = new JSONObject(new LinkedHashMap<>()); + + // 设置租户 + JSONObject jsonObject = commonAPI.setLoginTenant(loginUser.getUsername()); + addition.putAll(jsonObject.getInnerMap()); + // 设置登录用户信息 addition.put("userInfo", loginUser); addition.put("sysAllDictItems", commonAPI.queryAllDictItems()); @@ -190,6 +199,7 @@ public class PhoneGrantAuthenticationProvider implements AuthenticationProvider addition.put("multi_depart", 2); } + // 返回access_token、refresh_token以及其它信息给到前端 return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, addition); } diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/phone/PhoneGrantAuthenticationToken.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/phone/PhoneGrantAuthenticationToken.java index 68110cf6..b2f25b7f 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/phone/PhoneGrantAuthenticationToken.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/phone/PhoneGrantAuthenticationToken.java @@ -8,6 +8,7 @@ import org.springframework.security.oauth2.server.authorization.authentication.O import java.util.Map; /** + * 手机号模式认证专用token类型,方法spring authorization server进行认证流转,配合convert使用 * @author EightMonth * @date 2024/1/1 */ diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/social/SocialGrantAuthenticationConvert.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/social/SocialGrantAuthenticationConvert.java index 67a43bd3..142af6f1 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/social/SocialGrantAuthenticationConvert.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/social/SocialGrantAuthenticationConvert.java @@ -16,6 +16,7 @@ import java.util.HashMap; import java.util.Map; /** + * 社交模式认证转换器,配合github、企业微信、钉钉、微信登录使用 * @author EightMonth * @date 2024/1/1 */ diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/social/SocialGrantAuthenticationProvider.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/social/SocialGrantAuthenticationProvider.java index 9371dcd4..3fffd292 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/social/SocialGrantAuthenticationProvider.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/social/SocialGrantAuthenticationProvider.java @@ -1,5 +1,6 @@ package org.jeecg.config.security.social; +import com.alibaba.fastjson.JSONObject; import com.auth0.jwt.JWT; import com.auth0.jwt.interfaces.DecodedJWT; import lombok.extern.slf4j.Slf4j; @@ -38,6 +39,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; /** + * 社交模式认证处理器,负责处理该认证模式下的核心逻辑,配合github、企业微信、钉钉、微信登录使用 * @author EightMonth * @date 2024/1/1 */ @@ -84,6 +86,7 @@ public class SocialGrantAuthenticationProvider implements AuthenticationProvider DecodedJWT jwt = JWT.decode(token); String username = jwt.getClaim("username").asString(); + // 通过手机号获取用户信息 LoginUser loginUser = commonAPI.getUserByName(username); // 检查用户可行性 checkUserIsEffective(loginUser); @@ -152,11 +155,17 @@ public class SocialGrantAuthenticationProvider implements AuthenticationProvider OAuth2Authorization authorization = authorizationBuilder.build(); + // 保存认证信息至redis authorizationService.save(authorization); baseCommonService.addLog("用户名: " + loginUser.getUsername() + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser); - Map addition = new HashMap<>(); + JSONObject addition = new JSONObject(new LinkedHashMap<>()); + + // 设置租户 + JSONObject jsonObject = commonAPI.setLoginTenant(loginUser.getUsername()); + addition.putAll(jsonObject.getInnerMap()); + // 设置登录用户信息 addition.put("userInfo", loginUser); addition.put("sysAllDictItems", commonAPI.queryAllDictItems()); @@ -176,6 +185,7 @@ public class SocialGrantAuthenticationProvider implements AuthenticationProvider addition.put("multi_depart", 2); } + // 返回access_token、refresh_token以及其它信息给到前端 return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, addition); } diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/social/SocialGrantAuthenticationToken.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/social/SocialGrantAuthenticationToken.java index 455824d0..7ff4f37c 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/social/SocialGrantAuthenticationToken.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/social/SocialGrantAuthenticationToken.java @@ -8,6 +8,7 @@ import org.springframework.security.oauth2.server.authorization.authentication.O import java.util.Map; /** + * 社交模式认证专用token类型,方法spring authorization server进行认证流转,配合convert使用,配合github、企业微信、钉钉、微信登录使用 * @author EightMonth * @date 2024/1/1 */ diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/utils/SecureUtil.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/utils/SecureUtil.java index f9a416b7..60b1d5f5 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/utils/SecureUtil.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/utils/SecureUtil.java @@ -2,14 +2,20 @@ package org.jeecg.config.security.utils; import com.alibaba.fastjson2.JSONObject; import org.jeecg.common.system.vo.LoginUser; +import org.jeecg.common.util.SpringContextUtils; import org.springframework.security.core.context.SecurityContextHolder; /** + * 认证信息工具类 * @author EightMonth * @date 2024/1/10 17:03 */ public class SecureUtil { + /** + * 通过当前认证信息获取用户信息 + * @return + */ public static LoginUser currentUser() { String name = SecurityContextHolder.getContext().getAuthentication().getName(); return JSONObject.parseObject(name, LoginUser.class); diff --git a/jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java b/jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java index ce532e5d..7f999b03 100644 --- a/jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java +++ b/jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java @@ -749,4 +749,6 @@ public interface ISysBaseAPI extends CommonAPI { @PostMapping("/sys/api/updateUserDepart") void updateUserDepart(@RequestParam("username") String username,@RequestParam("orgCode") String orgCode,@RequestParam("loginTenantId") Integer loginTenantId); + @GetMapping("/sys/api/setLoginTenant") + JSONObject setLoginTenant(@RequestParam("username") String username); } diff --git a/jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/fallback/SysBaseAPIFallback.java b/jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/fallback/SysBaseAPIFallback.java index 55a331ea..8450a572 100644 --- a/jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/fallback/SysBaseAPIFallback.java +++ b/jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/fallback/SysBaseAPIFallback.java @@ -452,4 +452,9 @@ public class SysBaseAPIFallback implements ISysBaseAPI { public LoginUser getUserByPhone(String phone) { return null; } + + @Override + public JSONObject setLoginTenant(String username) { + return null; + } } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/api/controller/SystemApiController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/api/controller/SystemApiController.java index 6d3bee18..f42cb1af 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/api/controller/SystemApiController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/api/controller/SystemApiController.java @@ -917,4 +917,9 @@ public class SystemApiController { sysBaseApi.updateUserDepart(username, orgCode, loginTenantId); } + @GetMapping("/sys/api/setLoginTenant") + public JSONObject setLoginTenant(@RequestParam("username") String username) { + return sysBaseApi.setLoginTenant(username); + } + } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java index d45c7efb..f5f2b51a 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java @@ -20,6 +20,7 @@ import org.apache.commons.lang3.ObjectUtils; import org.jeecg.common.api.dto.DataLogDTO; import org.jeecg.common.api.dto.OnlineAuthDTO; import org.jeecg.common.api.dto.message.*; +import org.jeecg.common.api.vo.Result; import org.jeecg.common.aspect.UrlMatchEnum; import org.jeecg.common.config.TenantContext; import org.jeecg.common.constant.*; @@ -1780,4 +1781,11 @@ public class SysBaseApiImpl implements ISysBaseAPI { } } + @Override + public JSONObject setLoginTenant(String username) { + JSONObject obj = new JSONObject(new LinkedHashMap<>()); + SysUser sysUser = sysUserService.getUserByName(username); + sysUserService.setLoginTenant(sysUser, obj, username, null); + return obj; + } } \ No newline at end of file