refactor: 代码重构,移除 jjwt 的 JWT 库,使用 HuTool 工具实现 JWT 生成(默认jjwt库)、验证和解析。

This commit is contained in:
hxr
2024-01-20 23:19:02 +08:00
parent b1a4bb7109
commit 9403479af7
39 changed files with 254 additions and 315 deletions

View File

@@ -80,6 +80,10 @@ youlai-boot
├── websocket # WebSocket 插件,实时双向通信 ├── websocket # WebSocket 插件,实时双向通信
├── xxljob # XXL-JOB 插件,分布式任务调度和执行 ├── xxljob # XXL-JOB 插件,分布式任务调度和执行
├── service # 业务逻辑层 ├── service # 业务逻辑层
├── util # 工具类
├── JwtUtils # JWT 工具类
├── SecurityUtils # Spring Security 工具类
└── end └── end
``` ```

31
pom.xml
View File

@@ -6,7 +6,7 @@
<groupId>com.youlai</groupId> <groupId>com.youlai</groupId>
<artifactId>youlai-boot</artifactId> <artifactId>youlai-boot</artifactId>
<version>2.5.3</version> <version>2.6.0</version>
<description>基于 Java 17 + SpringBoot 3 构建的权限管理系统。</description> <description>基于 Java 17 + SpringBoot 3 构建的权限管理系统。</description>
<parent> <parent>
@@ -33,8 +33,6 @@
<xxl-job.version>2.4.0</xxl-job.version> <xxl-job.version>2.4.0</xxl-job.version>
<jjwt.version>0.11.5</jjwt.version>
<easyexcel.version>3.2.1</easyexcel.version> <easyexcel.version>3.2.1</easyexcel.version>
<!-- 对象存储 --> <!-- 对象存储 -->
@@ -119,16 +117,10 @@
<dependency> <dependency>
<groupId>com.baomidou</groupId> <groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId> <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus.version}</version> <version>${mybatis-plus.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.3</version>
</dependency>
<dependency> <dependency>
<groupId>com.github.xiaoymin</groupId> <groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId> <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
@@ -153,25 +145,6 @@
<version>${xxl-job.version}</version> <version>${xxl-job.version}</version>
</dependency> </dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId> <artifactId>easyexcel</artifactId>

View File

@@ -192,6 +192,7 @@ public class GlobalExceptionHandler {
throw e; throw e;
} }
log.error("unknown exception: {}", e.getMessage()); log.error("unknown exception: {}", e.getMessage());
e.printStackTrace();
return Result.failed(e.getLocalizedMessage()); return Result.failed(e.getLocalizedMessage());
} }

View File

@@ -3,9 +3,8 @@ package com.youlai.system.config;
import com.youlai.system.common.constant.SecurityConstants; import com.youlai.system.common.constant.SecurityConstants;
import com.youlai.system.core.security.exception.MyAccessDeniedHandler; import com.youlai.system.core.security.exception.MyAccessDeniedHandler;
import com.youlai.system.core.security.exception.MyAuthenticationEntryPoint; 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.filter.VerifyCodeFilter;
import com.youlai.system.core.security.jwt.JwtTokenProvider;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -36,7 +35,6 @@ public class SecurityConfig {
private final MyAuthenticationEntryPoint authenticationEntryPoint; private final MyAuthenticationEntryPoint authenticationEntryPoint;
private final MyAccessDeniedHandler accessDeniedHandler; private final MyAccessDeniedHandler accessDeniedHandler;
private final JwtTokenProvider jwtTokenProvider;
@Bean @Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
@@ -58,7 +56,7 @@ public class SecurityConfig {
// 验证码校验过滤器 // 验证码校验过滤器
http.addFilterBefore(new VerifyCodeFilter(), UsernamePasswordAuthenticationFilter.class); http.addFilterBefore(new VerifyCodeFilter(), UsernamePasswordAuthenticationFilter.class);
// JWT 校验过滤器 // JWT 校验过滤器
http.addFilterBefore(new JwtTokenFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class); http.addFilterBefore(new JwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build(); return http.build();
} }

View File

@@ -1,8 +1,7 @@
package com.youlai.system.config; package com.youlai.system.config;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.youlai.system.core.security.jwt.JwtTokenProvider; import com.youlai.system.util.JwtUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
@@ -26,12 +25,9 @@ import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerCo
*/ */
@Configuration @Configuration
@EnableWebSocketMessageBroker // 启用WebSocket消息代理功能和配置STOMP协议实现实时双向通信和消息传递 @EnableWebSocketMessageBroker // 启用WebSocket消息代理功能和配置STOMP协议实现实时双向通信和消息传递
@RequiredArgsConstructor
@Slf4j @Slf4j
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { 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 ")) { if (StrUtil.isNotBlank(bearerToken) && bearerToken.startsWith("Bearer ")) {
try { try {
// 移除 "Bearer " 前缀,从令牌中提取用户信息(username), 并设置到认证信息中 // 移除 "Bearer " 前缀,从令牌中提取用户信息(username), 并设置到认证信息中
String tokenWithoutPrefix = bearerToken.substring(7); String username = JwtUtils.parseToken(bearerToken).get("name").toString();
String username = jwtTokenProvider.getUsername(tokenWithoutPrefix);
if (StrUtil.isNotBlank(username)) { if (StrUtil.isNotBlank(username)) {
accessor.setUser(() -> username); accessor.setUser(() -> username);

View File

@@ -6,7 +6,7 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.youlai.system.common.result.PageResult; import com.youlai.system.common.result.PageResult;
import com.youlai.system.common.result.Result; 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.dupsubmit.annotation.PreventDuplicateSubmit;
import com.youlai.system.plugin.easyexcel.UserImportListener; import com.youlai.system.plugin.easyexcel.UserImportListener;
import com.youlai.system.model.vo.UserImportVO; import com.youlai.system.model.vo.UserImportVO;

View File

@@ -23,7 +23,7 @@ import org.mapstruct.Mappings;
public interface UserConverter { public interface UserConverter {
@Mappings({ @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); UserPageVO toPageVo(UserBO bo);

View File

@@ -5,8 +5,8 @@ import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler; import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler;
import com.youlai.system.core.mybatis.annotation.DataPermission; import com.youlai.system.core.mybatis.annotation.DataPermission;
import com.youlai.system.common.base.IBaseEnum; import com.youlai.system.common.base.IBaseEnum;
import com.youlai.system.common.enums.DataScopeEnum; import com.youlai.system.enums.DataScopeEnum;
import com.youlai.system.common.util.SecurityUtils; import com.youlai.system.util.SecurityUtils;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.Expression;

View File

@@ -1,7 +1,7 @@
package com.youlai.system.core.security.exception; package com.youlai.system.core.security.exception;
import com.youlai.system.common.result.ResultCode; 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.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;

View File

@@ -1,7 +1,7 @@
package com.youlai.system.core.security.exception; package com.youlai.system.core.security.exception;
import com.youlai.system.common.result.ResultCode; 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.authentication.BadCredentialsException;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.AuthenticationEntryPoint;

View File

@@ -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 工具类
* <p>
* 用于生成/校验/解析 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;
/**
* 初始化方法
* <p>
* 对签名密钥进行 Base64 编码
*/
@PostConstruct
protected void init() {
secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes());
}
/**
* 创建Token
* <p>
* 认证成功后的用户信息会被封装到 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<String> 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<SimpleGrantedAuthority> authorities = ((ArrayList<String>) 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的Claimsclaims中包含了用户的基本信息
*
* @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;
}
}

View File

@@ -3,7 +3,7 @@ package com.youlai.system.core.security.service;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.youlai.system.common.constant.CacheConstants; 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.model.bo.RolePermsBO;
import com.youlai.system.service.SysRoleMenuService; import com.youlai.system.service.SysRoleMenuService;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;

View File

@@ -1,4 +1,4 @@
package com.youlai.system.common.enums; package com.youlai.system.enums;
/** /**
* EasyCaptcha 验证码类型枚举 * EasyCaptcha 验证码类型枚举

View File

@@ -1,4 +1,4 @@
package com.youlai.system.common.enums; package com.youlai.system.enums;
import com.youlai.system.common.base.IBaseEnum; import com.youlai.system.common.base.IBaseEnum;
import lombok.Getter; import lombok.Getter;

View File

@@ -1,4 +1,4 @@
package com.youlai.system.common.enums; package com.youlai.system.enums;
import com.youlai.system.common.base.IBaseEnum; import com.youlai.system.common.base.IBaseEnum;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;

View File

@@ -1,4 +1,4 @@
package com.youlai.system.common.enums; package com.youlai.system.enums;
import com.baomidou.mybatisplus.annotation.EnumValue; import com.baomidou.mybatisplus.annotation.EnumValue;
import com.youlai.system.common.base.IBaseEnum; import com.youlai.system.common.base.IBaseEnum;

View File

@@ -1,4 +1,4 @@
package com.youlai.system.common.enums; package com.youlai.system.enums;
import com.youlai.system.common.base.IBaseEnum; import com.youlai.system.common.base.IBaseEnum;
import lombok.Getter; import lombok.Getter;

View File

@@ -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.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 com.youlai.system.common.exception.BusinessException;
import jakarta.servlet.FilterChain; import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; 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.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException; import java.io.IOException;
import java.util.Map;
/** /**
* JWT token 过滤器 * JWT token 过滤器
@@ -21,15 +31,6 @@ import java.io.IOException;
*/ */
public class JwtTokenFilter extends OncePerRequestFilter { public class JwtTokenFilter extends OncePerRequestFilter {
/**
* JWT Token 工具类
*/
private JwtTokenProvider jwtTokenProvider;
public JwtTokenFilter(JwtTokenProvider jwtTokenProvider) {
this.jwtTokenProvider = jwtTokenProvider;
}
/** /**
* 从请求中获取 JWT Token校验 JWT Token 是否合法 * 从请求中获取 JWT Token校验 JWT Token 是否合法
* <p> * <p>
@@ -38,11 +39,21 @@ public class JwtTokenFilter extends OncePerRequestFilter {
*/ */
@Override @Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String token = jwtTokenProvider.resolveToken(request); String token = request.getHeader(HttpHeaders.AUTHORIZATION);
try { try {
if (token != null && jwtTokenProvider.validateToken(token)) { if (StrUtil.isNotBlank(token)) {
Authentication auth = jwtTokenProvider.getAuthentication(token); Map<String, Object> payload = JwtUtils.parseToken(token);
SecurityContextHolder.getContext().setAuthentication(auth); 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) { } catch (BusinessException ex) {
//this is very important, since it guarantees the user is not authenticated at all //this is very important, since it guarantees the user is not authenticated at all

View File

@@ -6,7 +6,7 @@ import cn.hutool.extra.spring.SpringUtil;
import com.youlai.system.common.constant.CacheConstants; import com.youlai.system.common.constant.CacheConstants;
import com.youlai.system.common.constant.SecurityConstants; import com.youlai.system.common.constant.SecurityConstants;
import com.youlai.system.common.result.ResultCode; 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.FilterChain;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;

View File

@@ -1,6 +1,6 @@
package com.youlai.system.model.bo; package com.youlai.system.model.bo;
import com.youlai.system.common.enums.MenuTypeEnum; import com.youlai.system.enums.MenuTypeEnum;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;

View File

@@ -5,7 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.youlai.system.common.base.BaseEntity; import com.youlai.system.common.base.BaseEntity;
import com.youlai.system.common.enums.MenuTypeEnum; import com.youlai.system.enums.MenuTypeEnum;
import lombok.Data; import lombok.Data;
/** /**

View File

@@ -1,7 +1,7 @@
package com.youlai.system.model.form; package com.youlai.system.model.form;
import com.fasterxml.jackson.annotation.JsonInclude; 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 io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;

View File

@@ -1,7 +1,7 @@
package com.youlai.system.model.vo; package com.youlai.system.model.vo;
import com.fasterxml.jackson.annotation.JsonInclude; 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 io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;

View File

@@ -1,10 +1,11 @@
package com.youlai.system.plugin.dupsubmit.aspect; package com.youlai.system.plugin.dupsubmit.aspect;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.youlai.system.plugin.dupsubmit.annotation.PreventDuplicateSubmit; import com.youlai.system.plugin.dupsubmit.annotation.PreventDuplicateSubmit;
import com.youlai.system.common.result.ResultCode; import com.youlai.system.common.result.ResultCode;
import com.youlai.system.common.exception.BusinessException; 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 jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -14,6 +15,7 @@ import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.annotation.Pointcut;
import org.redisson.api.RLock; import org.redisson.api.RLock;
import org.redisson.api.RedissonClient; import org.redisson.api.RedissonClient;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
@@ -33,11 +35,6 @@ import java.util.concurrent.TimeUnit;
public class DuplicateSubmitAspect { public class DuplicateSubmitAspect {
private final RedissonClient redissonClient; private final RedissonClient redissonClient;
/**
* JWT token 工具类
*/
private final JwtTokenProvider jwtTokenProvider;
private static final String RESUBMIT_LOCK_PREFIX = "LOCK:RESUBMIT:"; private static final String RESUBMIT_LOCK_PREFIX = "LOCK:RESUBMIT:";
/** /**
@@ -71,9 +68,9 @@ public class DuplicateSubmitAspect {
String resubmitLockKey = null; String resubmitLockKey = null;
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = jwtTokenProvider.resolveToken(request); String token = request.getHeader(HttpHeaders.AUTHORIZATION);
if (StrUtil.isNotBlank(token)) { 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(); resubmitLockKey = RESUBMIT_LOCK_PREFIX + jti + ":" + request.getMethod() + "-" + request.getRequestURI();
} }
return resubmitLockKey; return resubmitLockKey;

View File

@@ -9,8 +9,8 @@ import com.alibaba.excel.context.AnalysisContext;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.youlai.system.common.base.IBaseEnum; import com.youlai.system.common.base.IBaseEnum;
import com.youlai.system.common.constant.SystemConstants; import com.youlai.system.common.constant.SystemConstants;
import com.youlai.system.common.enums.GenderEnum; import com.youlai.system.enums.GenderEnum;
import com.youlai.system.common.enums.StatusEnum; import com.youlai.system.enums.StatusEnum;
import com.youlai.system.converter.UserConverter; import com.youlai.system.converter.UserConverter;
import com.youlai.system.model.entity.SysRole; import com.youlai.system.model.entity.SysRole;
import com.youlai.system.model.entity.SysUser; import com.youlai.system.model.entity.SysUser;

View File

@@ -3,20 +3,22 @@ package com.youlai.system.service.impl;
import cn.hutool.captcha.AbstractCaptcha; import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.CaptchaUtil; import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.generator.CodeGenerator; import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWTPayload;
import com.youlai.system.common.constant.CacheConstants; import com.youlai.system.common.constant.CacheConstants;
import com.youlai.system.common.enums.CaptchaTypeEnum; import com.youlai.system.enums.CaptchaTypeEnum;
import com.youlai.system.core.security.jwt.JwtTokenProvider;
import com.youlai.system.model.dto.CaptchaResult; import com.youlai.system.model.dto.CaptchaResult;
import com.youlai.system.model.dto.LoginResult; import com.youlai.system.model.dto.LoginResult;
import com.youlai.system.plugin.captcha.CaptchaProperties; import com.youlai.system.plugin.captcha.CaptchaProperties;
import com.youlai.system.service.AuthService; import com.youlai.system.service.AuthService;
import io.jsonwebtoken.Claims; import com.youlai.system.util.JwtUtils;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication; 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 org.springframework.web.context.request.ServletRequestAttributes;
import java.awt.*; import java.awt.*;
import java.util.Date; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
@@ -42,7 +44,6 @@ public class AuthServiceImpl implements AuthService {
private final AuthenticationManager authenticationManager; private final AuthenticationManager authenticationManager;
private final StringRedisTemplate redisTemplate; private final StringRedisTemplate redisTemplate;
private final JwtTokenProvider jwtTokenProvider;
private final CodeGenerator codeGenerator; private final CodeGenerator codeGenerator;
private final Font captchaFont; private final Font captchaFont;
private final CaptchaProperties captchaProperties; private final CaptchaProperties captchaProperties;
@@ -59,7 +60,7 @@ public class AuthServiceImpl implements AuthService {
UsernamePasswordAuthenticationToken authenticationToken = UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(username.toLowerCase().trim(), password); new UsernamePasswordAuthenticationToken(username.toLowerCase().trim(), password);
Authentication authentication = authenticationManager.authenticate(authenticationToken); Authentication authentication = authenticationManager.authenticate(authenticationToken);
String accessToken = jwtTokenProvider.createToken(authentication); String accessToken = JwtUtils.generateToken(authentication);
return LoginResult.builder() return LoginResult.builder()
.tokenType("Bearer") .tokenType("Bearer")
.accessToken(accessToken) .accessToken(accessToken)
@@ -72,15 +73,15 @@ public class AuthServiceImpl implements AuthService {
@Override @Override
public void logout() { public void logout() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = jwtTokenProvider.resolveToken(request); String token = request.getHeader(HttpHeaders.AUTHORIZATION);
if (StrUtil.isNotBlank(token)) { if (StrUtil.isNotBlank(token)) {
Claims claims = jwtTokenProvider.getTokenClaims(token);
String jti = claims.get("jti", String.class);
Date expiration = claims.getExpiration(); Map<String, Object> 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) { if (expiration != null) {
long ttl = expiration.getTime() - System.currentTimeMillis(); long ttl = expiration - System.currentTimeMillis() / 1000;
redisTemplate.opsForValue().set(CacheConstants.BLACKLIST_TOKEN_PREFIX + jti, null, ttl, TimeUnit.MILLISECONDS); redisTemplate.opsForValue().set(CacheConstants.BLACKLIST_TOKEN_PREFIX + jti, null, ttl, TimeUnit.SECONDS);
} else { } else {
redisTemplate.opsForValue().set(CacheConstants.BLACKLIST_TOKEN_PREFIX + jti, null); redisTemplate.opsForValue().set(CacheConstants.BLACKLIST_TOKEN_PREFIX + jti, null);
} }

View File

@@ -6,7 +6,7 @@ import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.system.common.constant.SystemConstants; 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.converter.DeptConverter;
import com.youlai.system.mapper.SysDeptMapper; import com.youlai.system.mapper.SysDeptMapper;
import com.youlai.system.model.entity.SysDept; import com.youlai.system.model.entity.SysDept;

View File

@@ -7,8 +7,8 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.system.common.constant.SystemConstants; import com.youlai.system.common.constant.SystemConstants;
import com.youlai.system.common.enums.MenuTypeEnum; import com.youlai.system.enums.MenuTypeEnum;
import com.youlai.system.common.enums.StatusEnum; import com.youlai.system.enums.StatusEnum;
import com.youlai.system.common.model.Option; import com.youlai.system.common.model.Option;
import com.youlai.system.converter.MenuConverter; import com.youlai.system.converter.MenuConverter;
import com.youlai.system.mapper.SysMenuMapper; import com.youlai.system.mapper.SysMenuMapper;

View File

@@ -20,7 +20,7 @@ import com.youlai.system.model.vo.RolePageVO;
import com.youlai.system.service.SysRoleMenuService; import com.youlai.system.service.SysRoleMenuService;
import com.youlai.system.service.SysRoleService; import com.youlai.system.service.SysRoleService;
import com.youlai.system.service.SysUserRoleService; import com.youlai.system.service.SysUserRoleService;
import com.youlai.system.common.util.SecurityUtils; import com.youlai.system.util.SecurityUtils;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;

View File

@@ -8,12 +8,10 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 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.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.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.mapper.SysUserMapper;
import com.youlai.system.model.dto.UserAuthInfo; import com.youlai.system.model.dto.UserAuthInfo;
import com.youlai.system.model.bo.UserBO; import com.youlai.system.model.bo.UserBO;
@@ -32,7 +30,6 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;

View File

@@ -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.DateTime;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;

View File

@@ -1,4 +1,4 @@
package com.youlai.system.common.util; package com.youlai.system.util;
import com.alibaba.excel.EasyExcel; import com.alibaba.excel.EasyExcel;
import com.youlai.system.plugin.easyexcel.MyAnalysisEventListener; import com.youlai.system.plugin.easyexcel.MyAnalysisEventListener;

View File

@@ -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
* <p>
* 认证成功后的用户信息会被封装到 Authentication 对象中,然后通过 JwtTokenProvider#createToken(Authentication) 方法创建 Token 字符串
*
* @param authentication 用户认证信息
* @return Token 字符串
*/
public static String generateToken(Authentication authentication) {
SysUserDetails userDetails = (SysUserDetails) authentication.getPrincipal();
Map<String, Object> 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<String> 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<String, Object> 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<String, Object> 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<SimpleGrantedAuthority> 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);
}
}

View File

@@ -1,4 +1,4 @@
package com.youlai.system.common.util; package com.youlai.system.util;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import com.youlai.system.common.result.IResultCode; import com.youlai.system.common.result.IResultCode;

View File

@@ -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.collection.CollectionUtil;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
@@ -49,8 +49,7 @@ public class SecurityUtils {
* @return * @return
*/ */
public static Long getDeptId() { public static Long getDeptId() {
Long userId = Convert.toLong(getUser().getDeptId()); return Convert.toLong(getUser().getDeptId());
return userId;
} }
/** /**
@@ -59,8 +58,7 @@ public class SecurityUtils {
* @return DataScope * @return DataScope
*/ */
public static Integer getDataScope() { public static Integer getDataScope() {
Integer dataScope = Convert.toInt(getUser().getDataScope()); return Convert.toInt(getUser().getDataScope());
return dataScope;
} }
@@ -74,10 +72,9 @@ public class SecurityUtils {
if (authentication != null) { if (authentication != null) {
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities(); Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
if (CollectionUtil.isNotEmpty(authorities)) { if (CollectionUtil.isNotEmpty(authorities)) {
Set<String> 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_")) .map(item -> StrUtil.removePrefix(item.getAuthority(), "ROLE_"))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
return roles;
} }
} }
return Collections.EMPTY_SET; return Collections.EMPTY_SET;
@@ -93,10 +90,10 @@ public class SecurityUtils {
if (authentication != null) { if (authentication != null) {
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities(); Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
if (CollectionUtil.isNotEmpty(authorities)) { if (CollectionUtil.isNotEmpty(authorities)) {
Set<String> perms = authorities.stream().filter(item -> !item.getAuthority().startsWith("ROLE_")) return authorities.stream()
.map(item -> item.getAuthority()) .map(GrantedAuthority::getAuthority)
.filter(authority -> !authority.startsWith("ROLE_"))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
return perms;
} }
} }
return Collections.EMPTY_SET; return Collections.EMPTY_SET;
@@ -111,11 +108,7 @@ public class SecurityUtils {
*/ */
public static boolean isRoot() { public static boolean isRoot() {
Set<String> roles = getRoles(); Set<String> roles = getRoles();
return roles.contains(SystemConstants.ROOT_ROLE_CODE);
if (roles.contains(SystemConstants.ROOT_ROLE_CODE)) {
return true;
}
return false;
} }
@@ -134,8 +127,7 @@ public class SecurityUtils {
Set<String> perms = getPerms(); Set<String> perms = getPerms();
boolean hasPerm = perms.stream().anyMatch(item -> PatternMatchUtils.simpleMatch(perm, item)); return perms.stream().anyMatch(item -> PatternMatchUtils.simpleMatch(perm, item));
return hasPerm;
} }
} }

View File

@@ -59,10 +59,10 @@ mybatis-plus:
# 认证配置 # 认证配置
jwt: jwt:
# 签署密钥 # 密钥
secret-key: SecretKey012345678901234567890123456789012345678901234567890123456789 key: SecretKey012345678901234567890123456789012345678901234567890123456789
# token 过期时间(单位:秒) # token 过期时间(单位:秒)
expiration: 7200 ttl: 7200
oss: oss:
# OSS 类型 (目前支持aliyun、minio) # OSS 类型 (目前支持aliyun、minio)

View File

@@ -59,10 +59,10 @@ mybatis-plus:
# 认证配置 # 认证配置
jwt: jwt:
# 签署密钥 # 密钥
secret-key: SecretKey012345678901234567890123456789012345678901234567890123456789 key: SecretKey012345678901234567890123456789012345678901234567890123456789
# token 过期时间(单位:秒) # token 过期时间(单位:秒)
expiration: 7200 ttl: 7200
oss: oss:
# OSS 类型 (目前支持aliyun、minio) # OSS 类型 (目前支持aliyun、minio)

View File

@@ -44,7 +44,7 @@
LEFT JOIN sys_role_menu t2 ON t1.id = t2.menu_id LEFT JOIN sys_role_menu t2 ON t1.id = t2.menu_id
LEFT JOIN sys_role t3 ON t2.role_id = t3.id LEFT JOIN sys_role t3 ON t2.role_id = t3.id
WHERE 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 ORDER BY t1.sort asc
</select> </select>
@@ -57,7 +57,7 @@
INNER JOIN sys_role_menu t2 ON t1.id = t2.menu_id INNER JOIN sys_role_menu t2 ON t1.id = t2.menu_id
INNER JOIN sys_role t3 ON t3.id = t2.role_id INNER JOIN sys_role t3 ON t3.id = t2.role_id
WHERE 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 AND t1.perm IS NOT NULL
<choose> <choose>
<when test="roles!=null and roles.size()>0"> <when test="roles!=null and roles.size()>0">

View File

@@ -33,7 +33,7 @@
INNER JOIN sys_role t2 ON t1.role_id = t2.id AND t2.deleted = 0 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 INNER JOIN sys_menu t3 ON t1.menu_id = t3.id
WHERE WHERE
type = '${@com.youlai.system.common.enums.MenuTypeEnum@BUTTON.getValue()}' type = '${@com.youlai.system.enums.MenuTypeEnum@BUTTON.getValue()}'
<if test="roleCode!=null and roleCode.trim() neq ''"> <if test="roleCode!=null and roleCode.trim() neq ''">
AND t2.`code` = #{roleCode} AND t2.`code` = #{roleCode}
</if> </if>