From 9403479af7ef2a5df337d68b1a18258723fe5cff Mon Sep 17 00:00:00 2001 From: hxr <1490493387@qq.com> Date: Sat, 20 Jan 2024 23:19:02 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BB=A3=E7=A0=81=E9=87=8D?= =?UTF-8?q?=E6=9E=84=EF=BC=8C=E7=A7=BB=E9=99=A4=20jjwt=20=E7=9A=84=20JWT?= =?UTF-8?q?=20=E5=BA=93=EF=BC=8C=E4=BD=BF=E7=94=A8=20HuTool=20=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E5=AE=9E=E7=8E=B0=20JWT=20=E7=94=9F=E6=88=90=EF=BC=88?= =?UTF-8?q?=E9=BB=98=E8=AE=A4jjwt=E5=BA=93=EF=BC=89=E3=80=81=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E5=92=8C=E8=A7=A3=E6=9E=90=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 + pom.xml | 31 +-- .../exception/GlobalExceptionHandler.java | 1 + .../youlai/system/config/SecurityConfig.java | 6 +- .../youlai/system/config/WebSocketConfig.java | 9 +- .../system/controller/SysUserController.java | 2 +- .../system/converter/UserConverter.java | 2 +- .../handler/MyDataPermissionHandler.java | 4 +- .../exception/MyAccessDeniedHandler.java | 2 +- .../exception/MyAuthenticationEntryPoint.java | 2 +- .../core/security/jwt/JwtTokenProvider.java | 182 ------------------ .../security/service/PermissionService.java | 2 +- .../{common => }/enums/CaptchaTypeEnum.java | 2 +- .../{common => }/enums/DataScopeEnum.java | 2 +- .../system/{common => }/enums/GenderEnum.java | 2 +- .../{common => }/enums/MenuTypeEnum.java | 2 +- .../system/{common => }/enums/StatusEnum.java | 2 +- .../jwt => filter}/JwtTokenFilter.java | 41 ++-- .../system/filter/VerifyCodeFilter.java | 2 +- .../com/youlai/system/model/bo/RouteBO.java | 2 +- .../youlai/system/model/entity/SysMenu.java | 2 +- .../youlai/system/model/form/MenuForm.java | 2 +- .../com/youlai/system/model/vo/MenuVO.java | 2 +- .../aspect/DuplicateSubmitAspect.java | 13 +- .../plugin/easyexcel/UserImportListener.java | 4 +- .../system/service/impl/AuthServiceImpl.java | 27 +-- .../service/impl/SysDeptServiceImpl.java | 2 +- .../service/impl/SysMenuServiceImpl.java | 4 +- .../service/impl/SysRoleServiceImpl.java | 2 +- .../service/impl/SysUserServiceImpl.java | 7 +- .../system/{common => }/util/DateUtils.java | 2 +- .../system/{common => }/util/ExcelUtils.java | 2 +- .../java/com/youlai/system/util/JwtUtils.java | 152 +++++++++++++++ .../{common => }/util/ResponseUtils.java | 2 +- .../{common => }/util/SecurityUtils.java | 26 +-- src/main/resources/application-dev.yml | 6 +- src/main/resources/application-prod.yml | 6 +- src/main/resources/mapper/SysMenuMapper.xml | 4 +- .../resources/mapper/SysRoleMenuMapper.xml | 2 +- 39 files changed, 254 insertions(+), 315 deletions(-) delete mode 100644 src/main/java/com/youlai/system/core/security/jwt/JwtTokenProvider.java rename src/main/java/com/youlai/system/{common => }/enums/CaptchaTypeEnum.java (89%) rename src/main/java/com/youlai/system/{common => }/enums/DataScopeEnum.java (93%) rename src/main/java/com/youlai/system/{common => }/enums/GenderEnum.java (92%) rename src/main/java/com/youlai/system/{common => }/enums/MenuTypeEnum.java (94%) rename src/main/java/com/youlai/system/{common => }/enums/StatusEnum.java (91%) rename src/main/java/com/youlai/system/{core/security/jwt => filter}/JwtTokenFilter.java (55%) rename src/main/java/com/youlai/system/{common => }/util/DateUtils.java (98%) rename src/main/java/com/youlai/system/{common => }/util/ExcelUtils.java (91%) create mode 100644 src/main/java/com/youlai/system/util/JwtUtils.java rename src/main/java/com/youlai/system/{common => }/util/ResponseUtils.java (97%) rename src/main/java/com/youlai/system/{common => }/util/SecurityUtils.java (80%) diff --git a/README.md b/README.md index 0336ca49..45a1fecb 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,10 @@ youlai-boot ├── websocket # WebSocket 插件,实时双向通信 ├── xxljob # XXL-JOB 插件,分布式任务调度和执行 ├── service # 业务逻辑层 + ├── util # 工具类 + ├── JwtUtils # JWT 工具类 + ├── SecurityUtils # Spring Security 工具类 + └── end ``` diff --git a/pom.xml b/pom.xml index 8bc61020..20574b6d 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.youlai youlai-boot - 2.5.3 + 2.6.0 基于 Java 17 + SpringBoot 3 构建的权限管理系统。 @@ -33,8 +33,6 @@ 2.4.0 - 0.11.5 - 3.2.1 @@ -119,16 +117,10 @@ com.baomidou - mybatis-plus-boot-starter + mybatis-plus-spring-boot3-starter ${mybatis-plus.version} - - org.mybatis - mybatis-spring - 3.0.3 - - com.github.xiaoymin knife4j-openapi3-jakarta-spring-boot-starter @@ -153,25 +145,6 @@ ${xxl-job.version} - - io.jsonwebtoken - jjwt-api - ${jjwt.version} - - - io.jsonwebtoken - jjwt-impl - ${jjwt.version} - runtime - - - - io.jsonwebtoken - jjwt-jackson - ${jjwt.version} - runtime - - com.alibaba easyexcel diff --git a/src/main/java/com/youlai/system/common/exception/GlobalExceptionHandler.java b/src/main/java/com/youlai/system/common/exception/GlobalExceptionHandler.java index ae7e9041..9b83b29c 100644 --- a/src/main/java/com/youlai/system/common/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/youlai/system/common/exception/GlobalExceptionHandler.java @@ -192,6 +192,7 @@ public class GlobalExceptionHandler { throw e; } log.error("unknown exception: {}", e.getMessage()); + e.printStackTrace(); return Result.failed(e.getLocalizedMessage()); } diff --git a/src/main/java/com/youlai/system/config/SecurityConfig.java b/src/main/java/com/youlai/system/config/SecurityConfig.java index 01896f04..1c799327 100644 --- a/src/main/java/com/youlai/system/config/SecurityConfig.java +++ b/src/main/java/com/youlai/system/config/SecurityConfig.java @@ -3,9 +3,8 @@ package com.youlai.system.config; import com.youlai.system.common.constant.SecurityConstants; import com.youlai.system.core.security.exception.MyAccessDeniedHandler; import com.youlai.system.core.security.exception.MyAuthenticationEntryPoint; -import com.youlai.system.core.security.jwt.JwtTokenFilter; +import com.youlai.system.filter.JwtTokenFilter; import com.youlai.system.filter.VerifyCodeFilter; -import com.youlai.system.core.security.jwt.JwtTokenProvider; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -36,7 +35,6 @@ public class SecurityConfig { private final MyAuthenticationEntryPoint authenticationEntryPoint; private final MyAccessDeniedHandler accessDeniedHandler; - private final JwtTokenProvider jwtTokenProvider; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { @@ -58,7 +56,7 @@ public class SecurityConfig { // 验证码校验过滤器 http.addFilterBefore(new VerifyCodeFilter(), UsernamePasswordAuthenticationFilter.class); // JWT 校验过滤器 - http.addFilterBefore(new JwtTokenFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class); + http.addFilterBefore(new JwtTokenFilter(), UsernamePasswordAuthenticationFilter.class); return http.build(); } diff --git a/src/main/java/com/youlai/system/config/WebSocketConfig.java b/src/main/java/com/youlai/system/config/WebSocketConfig.java index 9ef3eccc..fdcae54a 100644 --- a/src/main/java/com/youlai/system/config/WebSocketConfig.java +++ b/src/main/java/com/youlai/system/config/WebSocketConfig.java @@ -1,8 +1,7 @@ package com.youlai.system.config; import cn.hutool.core.util.StrUtil; -import com.youlai.system.core.security.jwt.JwtTokenProvider; -import lombok.RequiredArgsConstructor; +import com.youlai.system.util.JwtUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpHeaders; @@ -26,12 +25,9 @@ import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerCo */ @Configuration @EnableWebSocketMessageBroker // 启用WebSocket消息代理功能和配置STOMP协议,实现实时双向通信和消息传递 -@RequiredArgsConstructor @Slf4j public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { - private final JwtTokenProvider jwtTokenProvider; - /** * 注册一个端点,客户端通过这个端点进行连接 */ @@ -83,8 +79,7 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { if (StrUtil.isNotBlank(bearerToken) && bearerToken.startsWith("Bearer ")) { try { // 移除 "Bearer " 前缀,从令牌中提取用户信息(username), 并设置到认证信息中 - String tokenWithoutPrefix = bearerToken.substring(7); - String username = jwtTokenProvider.getUsername(tokenWithoutPrefix); + String username = JwtUtils.parseToken(bearerToken).get("name").toString(); if (StrUtil.isNotBlank(username)) { accessor.setUser(() -> username); diff --git a/src/main/java/com/youlai/system/controller/SysUserController.java b/src/main/java/com/youlai/system/controller/SysUserController.java index 86ebc436..28fdfd0d 100644 --- a/src/main/java/com/youlai/system/controller/SysUserController.java +++ b/src/main/java/com/youlai/system/controller/SysUserController.java @@ -6,7 +6,7 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.youlai.system.common.result.PageResult; import com.youlai.system.common.result.Result; -import com.youlai.system.common.util.ExcelUtils; +import com.youlai.system.util.ExcelUtils; import com.youlai.system.plugin.dupsubmit.annotation.PreventDuplicateSubmit; import com.youlai.system.plugin.easyexcel.UserImportListener; import com.youlai.system.model.vo.UserImportVO; diff --git a/src/main/java/com/youlai/system/converter/UserConverter.java b/src/main/java/com/youlai/system/converter/UserConverter.java index 8c88d2b3..4b9b0c61 100644 --- a/src/main/java/com/youlai/system/converter/UserConverter.java +++ b/src/main/java/com/youlai/system/converter/UserConverter.java @@ -23,7 +23,7 @@ import org.mapstruct.Mappings; public interface UserConverter { @Mappings({ - @Mapping(target = "genderLabel", expression = "java(com.youlai.system.common.base.IBaseEnum.getLabelByValue(bo.getGender(), com.youlai.system.common.enums.GenderEnum.class))") + @Mapping(target = "genderLabel", expression = "java(com.youlai.system.common.base.IBaseEnum.getLabelByValue(bo.getGender(), com.youlai.system.enums.GenderEnum.class))") }) UserPageVO toPageVo(UserBO bo); diff --git a/src/main/java/com/youlai/system/core/mybatis/handler/MyDataPermissionHandler.java b/src/main/java/com/youlai/system/core/mybatis/handler/MyDataPermissionHandler.java index b39f9b10..a0e67840 100644 --- a/src/main/java/com/youlai/system/core/mybatis/handler/MyDataPermissionHandler.java +++ b/src/main/java/com/youlai/system/core/mybatis/handler/MyDataPermissionHandler.java @@ -5,8 +5,8 @@ import com.baomidou.mybatisplus.core.toolkit.StringPool; import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler; import com.youlai.system.core.mybatis.annotation.DataPermission; import com.youlai.system.common.base.IBaseEnum; -import com.youlai.system.common.enums.DataScopeEnum; -import com.youlai.system.common.util.SecurityUtils; +import com.youlai.system.enums.DataScopeEnum; +import com.youlai.system.util.SecurityUtils; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import net.sf.jsqlparser.expression.Expression; diff --git a/src/main/java/com/youlai/system/core/security/exception/MyAccessDeniedHandler.java b/src/main/java/com/youlai/system/core/security/exception/MyAccessDeniedHandler.java index c7979301..5aaa3289 100644 --- a/src/main/java/com/youlai/system/core/security/exception/MyAccessDeniedHandler.java +++ b/src/main/java/com/youlai/system/core/security/exception/MyAccessDeniedHandler.java @@ -1,7 +1,7 @@ package com.youlai.system.core.security.exception; import com.youlai.system.common.result.ResultCode; -import com.youlai.system.common.util.ResponseUtils; +import com.youlai.system.util.ResponseUtils; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.stereotype.Component; diff --git a/src/main/java/com/youlai/system/core/security/exception/MyAuthenticationEntryPoint.java b/src/main/java/com/youlai/system/core/security/exception/MyAuthenticationEntryPoint.java index 368bdcef..43cd3997 100644 --- a/src/main/java/com/youlai/system/core/security/exception/MyAuthenticationEntryPoint.java +++ b/src/main/java/com/youlai/system/core/security/exception/MyAuthenticationEntryPoint.java @@ -1,7 +1,7 @@ package com.youlai.system.core.security.exception; import com.youlai.system.common.result.ResultCode; -import com.youlai.system.common.util.ResponseUtils; +import com.youlai.system.util.ResponseUtils; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; diff --git a/src/main/java/com/youlai/system/core/security/jwt/JwtTokenProvider.java b/src/main/java/com/youlai/system/core/security/jwt/JwtTokenProvider.java deleted file mode 100644 index 2f34d6c3..00000000 --- a/src/main/java/com/youlai/system/core/security/jwt/JwtTokenProvider.java +++ /dev/null @@ -1,182 +0,0 @@ -package com.youlai.system.core.security.jwt; - -import cn.hutool.core.convert.Convert; -import com.youlai.system.common.constant.JwtClaimConstants; -import com.youlai.system.core.security.model.SysUserDetails; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; -import io.jsonwebtoken.io.Decoders; -import io.jsonwebtoken.io.DecodingException; -import io.jsonwebtoken.security.Keys; -import jakarta.annotation.PostConstruct; -import jakarta.servlet.http.HttpServletRequest; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpHeaders; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.stereotype.Component; - -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.stream.Collectors; - -/** - * JWT token 工具类 - *

- * 用于生成/校验/解析 JWT Token - * - * @author haoxr - * @since 2023/9/13 - */ -@Component -public class JwtTokenProvider { - - /** - * 签名密钥,用于签名 Access Token - */ - @Value("${jwt.secret-key:123456}") - private String secretKey; - - @Value("${jwt.expiration:7200}") - private int expiration; - - /** - * Base64 编码后的签名密钥,用于校验/解析 Access Token - */ - private byte[] secretKeyBytes; - - - /** - * 初始化方法 - *

- * 对签名密钥进行 Base64 编码 - */ - @PostConstruct - protected void init() { - secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes()); - } - - /** - * 创建Token - *

- * 认证成功后的用户信息会被封装到 Authentication 对象中,然后通过 JwtTokenProvider#createToken(Authentication) 方法创建 Token 字符串 - * - * @param authentication 用户认证信息 - * @return Token 字符串 - */ - public String createToken(Authentication authentication) { - Claims claims = Jwts.claims().setSubject(authentication.getName()); - - SysUserDetails userDetails = (SysUserDetails) authentication.getPrincipal(); - claims.put(JwtClaimConstants.USER_ID, userDetails.getUserId()); // 用户ID - claims.put(JwtClaimConstants.USERNAME, claims.getSubject()); // 用户名 - claims.put(JwtClaimConstants.DEPT_ID, userDetails.getDeptId()); // 部门ID - claims.put(JwtClaimConstants.DATA_SCOPE, userDetails.getDataScope()); // 数据权限范围 - - // claims 中添加角色信息 - Set roles = userDetails.getAuthorities().stream() - .map(GrantedAuthority::getAuthority) - .collect(Collectors.toSet()); - claims.put(JwtClaimConstants.AUTHORITIES, roles); - - Date now = new Date(); - Date expirationTime = new Date(now.getTime() + expiration * 1000L); - return Jwts.builder() - .setClaims(claims) - .setIssuedAt(now) - .setExpiration(expirationTime) - .signWith(Keys.hmacShaKeyFor(getSecretKeyBytes()), SignatureAlgorithm.HS256).compact(); - } - - - /** - * 根据给定的令牌解析出用户认证信息 - * - * @param token JWT Token - * @return 用户认证信息 - */ - public Authentication getAuthentication(String token) { - Claims claims = this.getTokenClaims(token); - - SysUserDetails userDetails = new SysUserDetails(); - userDetails.setUserId(Convert.toLong(claims.get(JwtClaimConstants.USER_ID))); // 用户ID - userDetails.setUsername(Convert.toStr(claims.get(JwtClaimConstants.USERNAME))); // 用户名 - userDetails.setDeptId(Convert.toLong(claims.get(JwtClaimConstants.DEPT_ID))); // 部门ID - userDetails.setDataScope(Convert.toInt(claims.get(JwtClaimConstants.DATA_SCOPE))); // 数据权限范围 - - // 角色集合 - Set authorities = ((ArrayList) claims.get(JwtClaimConstants.AUTHORITIES)) - .stream() - .map(SimpleGrantedAuthority::new) - .collect(Collectors.toSet()); - - return new UsernamePasswordAuthenticationToken(userDetails, "", authorities); - } - - - /** - * 从请求头中获取Token - * - * @param req 请求对象 - * @return Token 字符串 - */ - public String resolveToken(HttpServletRequest req) { - String bearerToken = req.getHeader(HttpHeaders.AUTHORIZATION); - if (bearerToken != null && bearerToken.startsWith("Bearer ")) { - return bearerToken.substring(7); - } - return null; - } - - /** - * 校验Token是否有效 - * - * @param token JWT Token - * @return 是否有效 - */ - public boolean validateToken(String token) { - Jwts.parserBuilder().setSigningKey(getSecretKeyBytes()).build().parseClaimsJws(token); - return true; - } - - /** - * 获取Token中的用户名 - * - * @param token Token - * @return - */ - public String getUsername(String token) { - return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject(); - } - - /** - * 获取Token的Claims,claims中包含了用户的基本信息 - * - * @param token - * @return - */ - public Claims getTokenClaims(String token) { - return Jwts.parserBuilder().setSigningKey(this.getSecretKeyBytes()).build().parseClaimsJws(token).getBody(); - } - - /** - * 获取签名密钥的字节数组 - * - * @return 签名密钥的字节数组 - */ - public byte[] getSecretKeyBytes() { - if (secretKeyBytes == null) { - try { - secretKeyBytes = Decoders.BASE64.decode(secretKey); - } catch (DecodingException e) { - secretKeyBytes = secretKey.getBytes(StandardCharsets.UTF_8); - } - } - return secretKeyBytes; - } - - -} diff --git a/src/main/java/com/youlai/system/core/security/service/PermissionService.java b/src/main/java/com/youlai/system/core/security/service/PermissionService.java index b13b8784..f8c486ce 100644 --- a/src/main/java/com/youlai/system/core/security/service/PermissionService.java +++ b/src/main/java/com/youlai/system/core/security/service/PermissionService.java @@ -3,7 +3,7 @@ package com.youlai.system.core.security.service; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; import com.youlai.system.common.constant.CacheConstants; -import com.youlai.system.common.util.SecurityUtils; +import com.youlai.system.util.SecurityUtils; import com.youlai.system.model.bo.RolePermsBO; import com.youlai.system.service.SysRoleMenuService; import jakarta.annotation.PostConstruct; diff --git a/src/main/java/com/youlai/system/common/enums/CaptchaTypeEnum.java b/src/main/java/com/youlai/system/enums/CaptchaTypeEnum.java similarity index 89% rename from src/main/java/com/youlai/system/common/enums/CaptchaTypeEnum.java rename to src/main/java/com/youlai/system/enums/CaptchaTypeEnum.java index c2896d9e..b6376b1e 100644 --- a/src/main/java/com/youlai/system/common/enums/CaptchaTypeEnum.java +++ b/src/main/java/com/youlai/system/enums/CaptchaTypeEnum.java @@ -1,4 +1,4 @@ -package com.youlai.system.common.enums; +package com.youlai.system.enums; /** * EasyCaptcha 验证码类型枚举 diff --git a/src/main/java/com/youlai/system/common/enums/DataScopeEnum.java b/src/main/java/com/youlai/system/enums/DataScopeEnum.java similarity index 93% rename from src/main/java/com/youlai/system/common/enums/DataScopeEnum.java rename to src/main/java/com/youlai/system/enums/DataScopeEnum.java index 019a881d..09192e01 100644 --- a/src/main/java/com/youlai/system/common/enums/DataScopeEnum.java +++ b/src/main/java/com/youlai/system/enums/DataScopeEnum.java @@ -1,4 +1,4 @@ -package com.youlai.system.common.enums; +package com.youlai.system.enums; import com.youlai.system.common.base.IBaseEnum; import lombok.Getter; diff --git a/src/main/java/com/youlai/system/common/enums/GenderEnum.java b/src/main/java/com/youlai/system/enums/GenderEnum.java similarity index 92% rename from src/main/java/com/youlai/system/common/enums/GenderEnum.java rename to src/main/java/com/youlai/system/enums/GenderEnum.java index a576ec5d..22eff048 100644 --- a/src/main/java/com/youlai/system/common/enums/GenderEnum.java +++ b/src/main/java/com/youlai/system/enums/GenderEnum.java @@ -1,4 +1,4 @@ -package com.youlai.system.common.enums; +package com.youlai.system.enums; import com.youlai.system.common.base.IBaseEnum; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/src/main/java/com/youlai/system/common/enums/MenuTypeEnum.java b/src/main/java/com/youlai/system/enums/MenuTypeEnum.java similarity index 94% rename from src/main/java/com/youlai/system/common/enums/MenuTypeEnum.java rename to src/main/java/com/youlai/system/enums/MenuTypeEnum.java index 91b6c891..788bb6ac 100644 --- a/src/main/java/com/youlai/system/common/enums/MenuTypeEnum.java +++ b/src/main/java/com/youlai/system/enums/MenuTypeEnum.java @@ -1,4 +1,4 @@ -package com.youlai.system.common.enums; +package com.youlai.system.enums; import com.baomidou.mybatisplus.annotation.EnumValue; import com.youlai.system.common.base.IBaseEnum; diff --git a/src/main/java/com/youlai/system/common/enums/StatusEnum.java b/src/main/java/com/youlai/system/enums/StatusEnum.java similarity index 91% rename from src/main/java/com/youlai/system/common/enums/StatusEnum.java rename to src/main/java/com/youlai/system/enums/StatusEnum.java index ba6bf0bf..678afe16 100644 --- a/src/main/java/com/youlai/system/common/enums/StatusEnum.java +++ b/src/main/java/com/youlai/system/enums/StatusEnum.java @@ -1,4 +1,4 @@ -package com.youlai.system.common.enums; +package com.youlai.system.enums; import com.youlai.system.common.base.IBaseEnum; import lombok.Getter; diff --git a/src/main/java/com/youlai/system/core/security/jwt/JwtTokenFilter.java b/src/main/java/com/youlai/system/filter/JwtTokenFilter.java similarity index 55% rename from src/main/java/com/youlai/system/core/security/jwt/JwtTokenFilter.java rename to src/main/java/com/youlai/system/filter/JwtTokenFilter.java index 5fba6042..9e54bfd4 100644 --- a/src/main/java/com/youlai/system/core/security/jwt/JwtTokenFilter.java +++ b/src/main/java/com/youlai/system/filter/JwtTokenFilter.java @@ -1,17 +1,27 @@ -package com.youlai.system.core.security.jwt; +package com.youlai.system.filter; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.hutool.jwt.JWTPayload; +import com.youlai.system.common.constant.CacheConstants; import com.youlai.system.common.result.ResultCode; -import com.youlai.system.common.util.ResponseUtils; +import com.youlai.system.util.JwtUtils; +import com.youlai.system.util.ResponseUtils; import com.youlai.system.common.exception.BusinessException; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.http.HttpHeaders; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; +import java.util.Map; /** * JWT token 过滤器 @@ -21,15 +31,6 @@ import java.io.IOException; */ public class JwtTokenFilter extends OncePerRequestFilter { - /** - * JWT Token 工具类 - */ - private JwtTokenProvider jwtTokenProvider; - - public JwtTokenFilter(JwtTokenProvider jwtTokenProvider) { - this.jwtTokenProvider = jwtTokenProvider; - } - /** * 从请求中获取 JWT Token,校验 JWT Token 是否合法 *

@@ -38,11 +39,21 @@ public class JwtTokenFilter extends OncePerRequestFilter { */ @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - String token = jwtTokenProvider.resolveToken(request); + String token = request.getHeader(HttpHeaders.AUTHORIZATION); try { - if (token != null && jwtTokenProvider.validateToken(token)) { - Authentication auth = jwtTokenProvider.getAuthentication(token); - SecurityContextHolder.getContext().setAuthentication(auth); + if (StrUtil.isNotBlank(token)) { + Map payload = JwtUtils.parseToken(token); + String jti = Convert.toStr(payload.get(JWTPayload.JWT_ID)); + RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate", RedisTemplate.class); + Boolean isBlack = redisTemplate.hasKey(CacheConstants.BLACKLIST_TOKEN_PREFIX + jti); + + if (isBlack) { + ResponseUtils.writeErrMsg(response, ResultCode.TOKEN_INVALID); + return; + } + + Authentication authentication = JwtUtils.getAuthentication(payload); + SecurityContextHolder.getContext().setAuthentication(authentication); } } catch (BusinessException ex) { //this is very important, since it guarantees the user is not authenticated at all diff --git a/src/main/java/com/youlai/system/filter/VerifyCodeFilter.java b/src/main/java/com/youlai/system/filter/VerifyCodeFilter.java index d08ffdc2..5a304fba 100644 --- a/src/main/java/com/youlai/system/filter/VerifyCodeFilter.java +++ b/src/main/java/com/youlai/system/filter/VerifyCodeFilter.java @@ -6,7 +6,7 @@ import cn.hutool.extra.spring.SpringUtil; import com.youlai.system.common.constant.CacheConstants; import com.youlai.system.common.constant.SecurityConstants; import com.youlai.system.common.result.ResultCode; -import com.youlai.system.common.util.ResponseUtils; +import com.youlai.system.util.ResponseUtils; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; diff --git a/src/main/java/com/youlai/system/model/bo/RouteBO.java b/src/main/java/com/youlai/system/model/bo/RouteBO.java index 0cb9420e..9582415a 100644 --- a/src/main/java/com/youlai/system/model/bo/RouteBO.java +++ b/src/main/java/com/youlai/system/model/bo/RouteBO.java @@ -1,6 +1,6 @@ package com.youlai.system.model.bo; -import com.youlai.system.common.enums.MenuTypeEnum; +import com.youlai.system.enums.MenuTypeEnum; import lombok.Data; import java.util.List; diff --git a/src/main/java/com/youlai/system/model/entity/SysMenu.java b/src/main/java/com/youlai/system/model/entity/SysMenu.java index 0f0a3862..c494af7b 100644 --- a/src/main/java/com/youlai/system/model/entity/SysMenu.java +++ b/src/main/java/com/youlai/system/model/entity/SysMenu.java @@ -5,7 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.youlai.system.common.base.BaseEntity; -import com.youlai.system.common.enums.MenuTypeEnum; +import com.youlai.system.enums.MenuTypeEnum; import lombok.Data; /** diff --git a/src/main/java/com/youlai/system/model/form/MenuForm.java b/src/main/java/com/youlai/system/model/form/MenuForm.java index 7b16f6d0..0f761111 100644 --- a/src/main/java/com/youlai/system/model/form/MenuForm.java +++ b/src/main/java/com/youlai/system/model/form/MenuForm.java @@ -1,7 +1,7 @@ package com.youlai.system.model.form; import com.fasterxml.jackson.annotation.JsonInclude; -import com.youlai.system.common.enums.MenuTypeEnum; +import com.youlai.system.enums.MenuTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; diff --git a/src/main/java/com/youlai/system/model/vo/MenuVO.java b/src/main/java/com/youlai/system/model/vo/MenuVO.java index 3490e2f7..72ed36c9 100644 --- a/src/main/java/com/youlai/system/model/vo/MenuVO.java +++ b/src/main/java/com/youlai/system/model/vo/MenuVO.java @@ -1,7 +1,7 @@ package com.youlai.system.model.vo; import com.fasterxml.jackson.annotation.JsonInclude; -import com.youlai.system.common.enums.MenuTypeEnum; +import com.youlai.system.enums.MenuTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; diff --git a/src/main/java/com/youlai/system/plugin/dupsubmit/aspect/DuplicateSubmitAspect.java b/src/main/java/com/youlai/system/plugin/dupsubmit/aspect/DuplicateSubmitAspect.java index 23777e92..56d8f8ad 100644 --- a/src/main/java/com/youlai/system/plugin/dupsubmit/aspect/DuplicateSubmitAspect.java +++ b/src/main/java/com/youlai/system/plugin/dupsubmit/aspect/DuplicateSubmitAspect.java @@ -1,10 +1,11 @@ package com.youlai.system.plugin.dupsubmit.aspect; +import cn.hutool.core.convert.Convert; import cn.hutool.core.util.StrUtil; import com.youlai.system.plugin.dupsubmit.annotation.PreventDuplicateSubmit; import com.youlai.system.common.result.ResultCode; import com.youlai.system.common.exception.BusinessException; -import com.youlai.system.core.security.jwt.JwtTokenProvider; +import com.youlai.system.util.JwtUtils; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -14,6 +15,7 @@ import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; +import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; @@ -33,11 +35,6 @@ import java.util.concurrent.TimeUnit; public class DuplicateSubmitAspect { private final RedissonClient redissonClient; - - /** - * JWT token 工具类 - */ - private final JwtTokenProvider jwtTokenProvider; private static final String RESUBMIT_LOCK_PREFIX = "LOCK:RESUBMIT:"; /** @@ -71,9 +68,9 @@ public class DuplicateSubmitAspect { String resubmitLockKey = null; HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); - String token = jwtTokenProvider.resolveToken(request); + String token = request.getHeader(HttpHeaders.AUTHORIZATION); if (StrUtil.isNotBlank(token)) { - String jti = (String) jwtTokenProvider.getTokenClaims(token).get("jti"); + String jti = Convert.toStr(JwtUtils.parseToken(token).get("jti"), null); resubmitLockKey = RESUBMIT_LOCK_PREFIX + jti + ":" + request.getMethod() + "-" + request.getRequestURI(); } return resubmitLockKey; diff --git a/src/main/java/com/youlai/system/plugin/easyexcel/UserImportListener.java b/src/main/java/com/youlai/system/plugin/easyexcel/UserImportListener.java index 8a9bd4fb..573ce1a9 100644 --- a/src/main/java/com/youlai/system/plugin/easyexcel/UserImportListener.java +++ b/src/main/java/com/youlai/system/plugin/easyexcel/UserImportListener.java @@ -9,8 +9,8 @@ import com.alibaba.excel.context.AnalysisContext; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.youlai.system.common.base.IBaseEnum; import com.youlai.system.common.constant.SystemConstants; -import com.youlai.system.common.enums.GenderEnum; -import com.youlai.system.common.enums.StatusEnum; +import com.youlai.system.enums.GenderEnum; +import com.youlai.system.enums.StatusEnum; import com.youlai.system.converter.UserConverter; import com.youlai.system.model.entity.SysRole; import com.youlai.system.model.entity.SysUser; diff --git a/src/main/java/com/youlai/system/service/impl/AuthServiceImpl.java b/src/main/java/com/youlai/system/service/impl/AuthServiceImpl.java index 2c93349f..e0e1707c 100644 --- a/src/main/java/com/youlai/system/service/impl/AuthServiceImpl.java +++ b/src/main/java/com/youlai/system/service/impl/AuthServiceImpl.java @@ -3,20 +3,22 @@ package com.youlai.system.service.impl; import cn.hutool.captcha.AbstractCaptcha; import cn.hutool.captcha.CaptchaUtil; import cn.hutool.captcha.generator.CodeGenerator; +import cn.hutool.core.convert.Convert; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.jwt.JWTPayload; import com.youlai.system.common.constant.CacheConstants; -import com.youlai.system.common.enums.CaptchaTypeEnum; -import com.youlai.system.core.security.jwt.JwtTokenProvider; +import com.youlai.system.enums.CaptchaTypeEnum; import com.youlai.system.model.dto.CaptchaResult; import com.youlai.system.model.dto.LoginResult; import com.youlai.system.plugin.captcha.CaptchaProperties; import com.youlai.system.service.AuthService; -import io.jsonwebtoken.Claims; +import com.youlai.system.util.JwtUtils; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.http.HttpHeaders; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; @@ -26,7 +28,7 @@ import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import java.awt.*; -import java.util.Date; +import java.util.Map; import java.util.concurrent.TimeUnit; /** @@ -42,7 +44,6 @@ public class AuthServiceImpl implements AuthService { private final AuthenticationManager authenticationManager; private final StringRedisTemplate redisTemplate; - private final JwtTokenProvider jwtTokenProvider; private final CodeGenerator codeGenerator; private final Font captchaFont; private final CaptchaProperties captchaProperties; @@ -59,7 +60,7 @@ public class AuthServiceImpl implements AuthService { UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username.toLowerCase().trim(), password); Authentication authentication = authenticationManager.authenticate(authenticationToken); - String accessToken = jwtTokenProvider.createToken(authentication); + String accessToken = JwtUtils.generateToken(authentication); return LoginResult.builder() .tokenType("Bearer") .accessToken(accessToken) @@ -72,15 +73,15 @@ public class AuthServiceImpl implements AuthService { @Override public void logout() { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); - String token = jwtTokenProvider.resolveToken(request); + String token = request.getHeader(HttpHeaders.AUTHORIZATION); if (StrUtil.isNotBlank(token)) { - Claims claims = jwtTokenProvider.getTokenClaims(token); - String jti = claims.get("jti", String.class); - Date expiration = claims.getExpiration(); + Map claims = JwtUtils.parseToken(token); + String jti = Convert.toStr(claims.get(JWTPayload.JWT_ID)); + Long expiration = Convert.toLong(claims.get(JWTPayload.EXPIRES_AT)); if (expiration != null) { - long ttl = expiration.getTime() - System.currentTimeMillis(); - redisTemplate.opsForValue().set(CacheConstants.BLACKLIST_TOKEN_PREFIX + jti, null, ttl, TimeUnit.MILLISECONDS); + long ttl = expiration - System.currentTimeMillis() / 1000; + redisTemplate.opsForValue().set(CacheConstants.BLACKLIST_TOKEN_PREFIX + jti, null, ttl, TimeUnit.SECONDS); } else { redisTemplate.opsForValue().set(CacheConstants.BLACKLIST_TOKEN_PREFIX + jti, null); } @@ -123,7 +124,7 @@ public class AuthServiceImpl implements AuthService { // 验证码文本缓存至Redis,用于登录校验 String captchaKey = IdUtil.fastSimpleUUID(); - redisTemplate.opsForValue().set(CacheConstants.CAPTCHA_CODE_PREFIX + captchaKey,captchaCode, + redisTemplate.opsForValue().set(CacheConstants.CAPTCHA_CODE_PREFIX + captchaKey, captchaCode, captchaProperties.getExpireSeconds(), TimeUnit.SECONDS); return CaptchaResult.builder() diff --git a/src/main/java/com/youlai/system/service/impl/SysDeptServiceImpl.java b/src/main/java/com/youlai/system/service/impl/SysDeptServiceImpl.java index 0b703a08..7b53f3b6 100644 --- a/src/main/java/com/youlai/system/service/impl/SysDeptServiceImpl.java +++ b/src/main/java/com/youlai/system/service/impl/SysDeptServiceImpl.java @@ -6,7 +6,7 @@ import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.youlai.system.common.constant.SystemConstants; -import com.youlai.system.common.enums.StatusEnum; +import com.youlai.system.enums.StatusEnum; import com.youlai.system.converter.DeptConverter; import com.youlai.system.mapper.SysDeptMapper; import com.youlai.system.model.entity.SysDept; diff --git a/src/main/java/com/youlai/system/service/impl/SysMenuServiceImpl.java b/src/main/java/com/youlai/system/service/impl/SysMenuServiceImpl.java index af6cb85f..426649aa 100644 --- a/src/main/java/com/youlai/system/service/impl/SysMenuServiceImpl.java +++ b/src/main/java/com/youlai/system/service/impl/SysMenuServiceImpl.java @@ -7,8 +7,8 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.youlai.system.common.constant.SystemConstants; -import com.youlai.system.common.enums.MenuTypeEnum; -import com.youlai.system.common.enums.StatusEnum; +import com.youlai.system.enums.MenuTypeEnum; +import com.youlai.system.enums.StatusEnum; import com.youlai.system.common.model.Option; import com.youlai.system.converter.MenuConverter; import com.youlai.system.mapper.SysMenuMapper; diff --git a/src/main/java/com/youlai/system/service/impl/SysRoleServiceImpl.java b/src/main/java/com/youlai/system/service/impl/SysRoleServiceImpl.java index 5706ea36..269853b9 100644 --- a/src/main/java/com/youlai/system/service/impl/SysRoleServiceImpl.java +++ b/src/main/java/com/youlai/system/service/impl/SysRoleServiceImpl.java @@ -20,7 +20,7 @@ import com.youlai.system.model.vo.RolePageVO; import com.youlai.system.service.SysRoleMenuService; import com.youlai.system.service.SysRoleService; import com.youlai.system.service.SysUserRoleService; -import com.youlai.system.common.util.SecurityUtils; +import com.youlai.system.util.SecurityUtils; import lombok.RequiredArgsConstructor; import org.springframework.cache.annotation.CacheEvict; import org.springframework.stereotype.Service; diff --git a/src/main/java/com/youlai/system/service/impl/SysUserServiceImpl.java b/src/main/java/com/youlai/system/service/impl/SysUserServiceImpl.java index 82ece774..dab0d63f 100644 --- a/src/main/java/com/youlai/system/service/impl/SysUserServiceImpl.java +++ b/src/main/java/com/youlai/system/service/impl/SysUserServiceImpl.java @@ -8,12 +8,10 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.youlai.system.common.constant.CacheConstants; -import com.youlai.system.common.constant.SecurityConstants; import com.youlai.system.common.constant.SystemConstants; -import com.youlai.system.common.util.DateUtils; +import com.youlai.system.util.DateUtils; import com.youlai.system.converter.UserConverter; -import com.youlai.system.common.util.SecurityUtils; +import com.youlai.system.util.SecurityUtils; import com.youlai.system.mapper.SysUserMapper; import com.youlai.system.model.dto.UserAuthInfo; import com.youlai.system.model.bo.UserBO; @@ -32,7 +30,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Arrays; -import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; diff --git a/src/main/java/com/youlai/system/common/util/DateUtils.java b/src/main/java/com/youlai/system/util/DateUtils.java similarity index 98% rename from src/main/java/com/youlai/system/common/util/DateUtils.java rename to src/main/java/com/youlai/system/util/DateUtils.java index 6066bc7a..167fce20 100644 --- a/src/main/java/com/youlai/system/common/util/DateUtils.java +++ b/src/main/java/com/youlai/system/util/DateUtils.java @@ -1,5 +1,5 @@ -package com.youlai.system.common.util; +package com.youlai.system.util; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; diff --git a/src/main/java/com/youlai/system/common/util/ExcelUtils.java b/src/main/java/com/youlai/system/util/ExcelUtils.java similarity index 91% rename from src/main/java/com/youlai/system/common/util/ExcelUtils.java rename to src/main/java/com/youlai/system/util/ExcelUtils.java index d25921fe..14894baf 100644 --- a/src/main/java/com/youlai/system/common/util/ExcelUtils.java +++ b/src/main/java/com/youlai/system/util/ExcelUtils.java @@ -1,4 +1,4 @@ -package com.youlai.system.common.util; +package com.youlai.system.util; import com.alibaba.excel.EasyExcel; import com.youlai.system.plugin.easyexcel.MyAnalysisEventListener; diff --git a/src/main/java/com/youlai/system/util/JwtUtils.java b/src/main/java/com/youlai/system/util/JwtUtils.java new file mode 100644 index 00000000..af336b4e --- /dev/null +++ b/src/main/java/com/youlai/system/util/JwtUtils.java @@ -0,0 +1,152 @@ +package com.youlai.system.util; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.jwt.JWT; +import cn.hutool.jwt.JWTPayload; +import cn.hutool.jwt.JWTUtil; +import com.youlai.system.common.constant.JwtClaimConstants; +import com.youlai.system.core.security.model.SysUserDetails; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * JWT 工具类 + * + * @author haoxr + * @since 2.6.0 + */ +@Component +public class JwtUtils { + + private static byte[] key; + + + private static int ttl; + + + @Value("${jwt.key}") + public void setKey(String key) { + JwtUtils.key = key.getBytes(); + } + + @Value("${jwt.ttl}") + public void setTtl(Integer ttl) { + JwtUtils.ttl = ttl; + } + + /** + * 创建Token + *

+ * 认证成功后的用户信息会被封装到 Authentication 对象中,然后通过 JwtTokenProvider#createToken(Authentication) 方法创建 Token 字符串 + * + * @param authentication 用户认证信息 + * @return Token 字符串 + */ + public static String generateToken(Authentication authentication) { + + SysUserDetails userDetails = (SysUserDetails) authentication.getPrincipal(); + + + Map payload = new HashMap<>(); + payload.put(JwtClaimConstants.USER_ID, userDetails.getUserId()); // 用户ID + payload.put(JwtClaimConstants.DEPT_ID, userDetails.getDeptId()); // 部门ID + payload.put(JwtClaimConstants.DATA_SCOPE, userDetails.getDataScope()); // 数据权限范围 + + // claims 中添加角色信息 + Set roles = userDetails.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) + .collect(Collectors.toSet()); + payload.put(JwtClaimConstants.AUTHORITIES, roles); + + + Date now = new Date(); + Date expiration = DateUtil.offsetSecond(now, ttl); + payload.put(JWTPayload.ISSUED_AT, now); + payload.put(JWTPayload.EXPIRES_AT, expiration); + payload.put(JWTPayload.SUBJECT, authentication.getName()); + payload.put(JWTPayload.JWT_ID, IdUtil.simpleUUID()); + + return JWTUtil.createToken(payload, JwtUtils.key); + } + + /** + * 从 Token 中解析数据 + * + * @param token JWT Token + * @return 解析数据 + */ + public static Map parseToken(String token) { + try { + if (StrUtil.isBlank(token)) { + return null; + } + + if (token.startsWith("Bearer ")) { + token = token.substring(7); + } + + JWT jwt = JWTUtil.parseToken(token); + if (jwt.setKey(JwtUtils.key).validate(0)) { + return jwt.getPayloads(); + } + } catch (Exception ignored) { + } + return null; + } + + /** + * 从 Token 中获取 Authentication + * + * @param payload + * @return + */ + public static UsernamePasswordAuthenticationToken getAuthentication(Map payload) { + SysUserDetails userDetails = new SysUserDetails(); + userDetails.setUserId(Convert.toLong(payload.get(JwtClaimConstants.USER_ID))); // 用户ID + userDetails.setDeptId(Convert.toLong(payload.get(JwtClaimConstants.DEPT_ID))); // 部门ID + userDetails.setDataScope(Convert.toInt(payload.get(JwtClaimConstants.DATA_SCOPE))); // 数据权限范围 + + userDetails.setUsername(Convert.toStr(payload.get(JWTPayload.SUBJECT))); // 用户名 + // 角色集合 + Set authorities = ((JSONArray) payload.get(JwtClaimConstants.AUTHORITIES)) + .stream() + .map(authority -> new SimpleGrantedAuthority(Convert.toStr(authority))) + .collect(Collectors.toSet()); + + return new UsernamePasswordAuthenticationToken(userDetails, "", authorities); + } + + + /** + * 验证 JWT Token + * + * @param token JWT Token + * @return 是否有效 + */ + public static boolean verifyToken(String token) { + + if (StrUtil.isBlank(token)) { + return false; + } + + if (token.startsWith("Bearer ")) { + token = token.substring(7); + } + + JWT jwt = JWTUtil.parseToken(token); + return jwt.setKey(JwtUtils.key).validate(0); + + } + +} diff --git a/src/main/java/com/youlai/system/common/util/ResponseUtils.java b/src/main/java/com/youlai/system/util/ResponseUtils.java similarity index 97% rename from src/main/java/com/youlai/system/common/util/ResponseUtils.java rename to src/main/java/com/youlai/system/util/ResponseUtils.java index 2ed64175..5b702f26 100644 --- a/src/main/java/com/youlai/system/common/util/ResponseUtils.java +++ b/src/main/java/com/youlai/system/util/ResponseUtils.java @@ -1,4 +1,4 @@ -package com.youlai.system.common.util; +package com.youlai.system.util; import cn.hutool.json.JSONUtil; import com.youlai.system.common.result.IResultCode; diff --git a/src/main/java/com/youlai/system/common/util/SecurityUtils.java b/src/main/java/com/youlai/system/util/SecurityUtils.java similarity index 80% rename from src/main/java/com/youlai/system/common/util/SecurityUtils.java rename to src/main/java/com/youlai/system/util/SecurityUtils.java index 48a7631f..65de6f22 100644 --- a/src/main/java/com/youlai/system/common/util/SecurityUtils.java +++ b/src/main/java/com/youlai/system/util/SecurityUtils.java @@ -1,4 +1,4 @@ -package com.youlai.system.common.util; +package com.youlai.system.util; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.convert.Convert; @@ -49,8 +49,7 @@ public class SecurityUtils { * @return */ public static Long getDeptId() { - Long userId = Convert.toLong(getUser().getDeptId()); - return userId; + return Convert.toLong(getUser().getDeptId()); } /** @@ -59,8 +58,7 @@ public class SecurityUtils { * @return DataScope */ public static Integer getDataScope() { - Integer dataScope = Convert.toInt(getUser().getDataScope()); - return dataScope; + return Convert.toInt(getUser().getDataScope()); } @@ -74,10 +72,9 @@ public class SecurityUtils { if (authentication != null) { Collection authorities = authentication.getAuthorities(); if (CollectionUtil.isNotEmpty(authorities)) { - Set roles = authorities.stream().filter(item -> item.getAuthority().startsWith("ROLE_")) + return authorities.stream().filter(item -> item.getAuthority().startsWith("ROLE_")) .map(item -> StrUtil.removePrefix(item.getAuthority(), "ROLE_")) .collect(Collectors.toSet()); - return roles; } } return Collections.EMPTY_SET; @@ -93,10 +90,10 @@ public class SecurityUtils { if (authentication != null) { Collection authorities = authentication.getAuthorities(); if (CollectionUtil.isNotEmpty(authorities)) { - Set perms = authorities.stream().filter(item -> !item.getAuthority().startsWith("ROLE_")) - .map(item -> item.getAuthority()) + return authorities.stream() + .map(GrantedAuthority::getAuthority) + .filter(authority -> !authority.startsWith("ROLE_")) .collect(Collectors.toSet()); - return perms; } } return Collections.EMPTY_SET; @@ -111,11 +108,7 @@ public class SecurityUtils { */ public static boolean isRoot() { Set roles = getRoles(); - - if (roles.contains(SystemConstants.ROOT_ROLE_CODE)) { - return true; - } - return false; + return roles.contains(SystemConstants.ROOT_ROLE_CODE); } @@ -134,8 +127,7 @@ public class SecurityUtils { Set perms = getPerms(); - boolean hasPerm = perms.stream().anyMatch(item -> PatternMatchUtils.simpleMatch(perm, item)); - return hasPerm; + return perms.stream().anyMatch(item -> PatternMatchUtils.simpleMatch(perm, item)); } } diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index f33e8844..c91408be 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -59,10 +59,10 @@ mybatis-plus: # 认证配置 jwt: - # 签署密钥 - secret-key: SecretKey012345678901234567890123456789012345678901234567890123456789 + # 密钥 + key: SecretKey012345678901234567890123456789012345678901234567890123456789 # token 过期时间(单位:秒) - expiration: 7200 + ttl: 7200 oss: # OSS 类型 (目前支持aliyun、minio) diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index 561aa0c6..45c32fb8 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -59,10 +59,10 @@ mybatis-plus: # 认证配置 jwt: - # 签署密钥 - secret-key: SecretKey012345678901234567890123456789012345678901234567890123456789 + # 密钥 + key: SecretKey012345678901234567890123456789012345678901234567890123456789 # token 过期时间(单位:秒) - expiration: 7200 + ttl: 7200 oss: # OSS 类型 (目前支持aliyun、minio) diff --git a/src/main/resources/mapper/SysMenuMapper.xml b/src/main/resources/mapper/SysMenuMapper.xml index 83be7bae..667a24f9 100644 --- a/src/main/resources/mapper/SysMenuMapper.xml +++ b/src/main/resources/mapper/SysMenuMapper.xml @@ -44,7 +44,7 @@ LEFT JOIN sys_role_menu t2 ON t1.id = t2.menu_id LEFT JOIN sys_role t3 ON t2.role_id = t3.id WHERE - t1.type != '${@com.youlai.system.common.enums.MenuTypeEnum@BUTTON.getValue()}' + t1.type != '${@com.youlai.system.enums.MenuTypeEnum@BUTTON.getValue()}' ORDER BY t1.sort asc @@ -57,7 +57,7 @@ INNER JOIN sys_role_menu t2 ON t1.id = t2.menu_id INNER JOIN sys_role t3 ON t3.id = t2.role_id WHERE - t1.type = '${@com.youlai.system.common.enums.MenuTypeEnum@BUTTON.getValue()}' + t1.type = '${@com.youlai.system.enums.MenuTypeEnum@BUTTON.getValue()}' AND t1.perm IS NOT NULL diff --git a/src/main/resources/mapper/SysRoleMenuMapper.xml b/src/main/resources/mapper/SysRoleMenuMapper.xml index bcee8836..4f3487b2 100644 --- a/src/main/resources/mapper/SysRoleMenuMapper.xml +++ b/src/main/resources/mapper/SysRoleMenuMapper.xml @@ -33,7 +33,7 @@ INNER JOIN sys_role t2 ON t1.role_id = t2.id AND t2.deleted = 0 INNER JOIN sys_menu t3 ON t1.menu_id = t3.id WHERE - type = '${@com.youlai.system.common.enums.MenuTypeEnum@BUTTON.getValue()}' + type = '${@com.youlai.system.enums.MenuTypeEnum@BUTTON.getValue()}' AND t2.`code` = #{roleCode}