提交 95fdbc2c 编写于 作者: R Ray.Hao

refactor: 优化 `JWT` 解析和验证代码和修复用户名密码错误的异常提示

上级 69274645
......@@ -2,8 +2,10 @@ package com.youlai.system;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
@SpringBootApplication
@ConfigurationPropertiesScan
public class SystemApplication {
public static void main(String[] args) {
SpringApplication.run(SystemApplication.class, args);
......
package com.youlai.system.security.constant;
package com.youlai.system.common.constant;
/**
* JWT Claims声明常量
......
......@@ -24,4 +24,16 @@ public interface SecurityConstants {
String BLACKLIST_TOKEN_PREFIX = "token:blacklist:";
/**
* 登录路径
*/
String LOGIN_PATH = "/api/v1/auth/login";
/**
* JWT Token 前缀
*/
String JWT_TOKEN_PREFIX = "Bearer ";
}
package com.youlai.system.common.util;
import cn.hutool.json.JSONUtil;
import com.youlai.system.common.result.IResultCode;
import com.youlai.system.common.result.Result;
import com.youlai.system.common.result.ResultCode;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import static com.youlai.system.common.result.ResultCode.*;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
/**
* 响应工具类
*
* @author haoxr
* @author Ray Hao
* @since 2.0.0
*/
@Slf4j
public class ResponseUtils {
/**
* 异常消息返回(适用过滤器中处理异常响应)
*
* @param response
* @param resultCode
* @param response HttpServletResponse
* @param resultCode 响应结果码
*/
public static void writeErrMsg(HttpServletResponse response, ResultCode resultCode) throws IOException {
switch (resultCode) {
case ACCESS_UNAUTHORIZED:
case TOKEN_INVALID:
response.setStatus(HttpStatus.UNAUTHORIZED.value());
break;
case TOKEN_ACCESS_FORBIDDEN:
response.setStatus(HttpStatus.FORBIDDEN.value());
break;
default:
response.setStatus(HttpStatus.BAD_REQUEST.value());
break;
}
public static void writeErrMsg(HttpServletResponse response, ResultCode resultCode) {
// 根据不同的结果码设置HTTP状态
int status = switch (resultCode) {
case ACCESS_UNAUTHORIZED, TOKEN_INVALID -> HttpStatus.UNAUTHORIZED.value();
case TOKEN_ACCESS_FORBIDDEN -> HttpStatus.FORBIDDEN.value();
default -> HttpStatus.BAD_REQUEST.value();
};
response.setStatus(status);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("UTF-8");
response.getWriter().print(JSONUtil.toJsonStr(Result.failed(resultCode)));
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
try (PrintWriter writer = response.getWriter()) {
String jsonResponse = JSONUtil.toJsonStr(Result.failed(resultCode));
writer.print(jsonResponse);
writer.flush(); // 确保将响应内容写入到输出流
} catch (IOException e) {
log.error("响应异常处理失败", e);
}
}
}
package com.youlai.system.config;
import cn.hutool.captcha.generator.CodeGenerator;
import com.youlai.system.security.constant.SecurityConstants;
import cn.hutool.core.collection.CollectionUtil;
import com.youlai.system.common.constant.SecurityConstants;
import com.youlai.system.config.property.SecurityProperties;
import com.youlai.system.security.exception.MyAccessDeniedHandler;
import com.youlai.system.security.exception.MyAuthenticationEntryPoint;
import com.youlai.system.filter.JwtValidationFilter;
......@@ -17,6 +19,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
......@@ -26,7 +29,7 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
/**
* Spring Security 权限配置
*
* @author haoxr
* @author Ray Hao
* @since 2023/2/17
*/
@Configuration
......@@ -39,29 +42,33 @@ public class SecurityConfig {
private final MyAccessDeniedHandler accessDeniedHandler;
private final RedisTemplate<String, Object> redisTemplate;
private final CodeGenerator codeGenerator;
private final SecurityProperties securityProperties;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(requestMatcherRegistry ->
requestMatcherRegistry.requestMatchers(SecurityConstants.LOGIN_PATH).permitAll()
.anyRequest().authenticated()
)
.sessionManagement(configurer -> configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.exceptionHandling(httpSecurityExceptionHandlingConfigurer ->
httpSecurityExceptionHandlingConfigurer
.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(accessDeniedHandler)
)
.sessionManagement(configurer -> configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.csrf(AbstractHttpConfigurer::disable)
.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
;
// 验证码校验过滤器
http.addFilterBefore(new CaptchaValidationFilter(redisTemplate,codeGenerator), UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(new CaptchaValidationFilter(redisTemplate, codeGenerator), UsernamePasswordAuthenticationFilter.class);
// JWT 校验过滤器
http.addFilterBefore(new JwtValidationFilter(redisTemplate), UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(new JwtValidationFilter(redisTemplate,securityProperties.getJwt().getKey()), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
......@@ -71,18 +78,11 @@ public class SecurityConfig {
*/
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring()
.requestMatchers(
"/api/v1/auth/captcha",
"/webjars/**",
"/doc.html",
"/swagger-resources/**",
"/v3/api-docs/**",
"/swagger-ui/**",
"/swagger-ui.html",
"/ws/**",
"/ws-app/**"
);
return (web) -> {
if (CollectionUtil.isNotEmpty(securityProperties.getIgnoreUrls())) {
web.ignoring().requestMatchers(securityProperties.getIgnoreUrls().toArray(new String[0]));
}
};
}
/**
......
......@@ -2,7 +2,7 @@ package com.youlai.system.config;
import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWTPayload;
import com.youlai.system.security.util.JwtUtils;
import cn.hutool.jwt.JWTUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
......@@ -83,7 +83,7 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
// 这里不应该用"name"
// String username = JwtUtils.parseToken(bearerToken).get("name").toString();
String username = JwtUtils.parseToken(bearerToken).get(JWTPayload.SUBJECT).toString();
String username = JWTUtil.parseToken(bearerToken).getPayloads().getStr(JWTPayload.SUBJECT);
if (StrUtil.isNotBlank(username)) {
accessor.setUser(() -> username);
......
package com.youlai.system.config.property;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
/**
* @author haoxr
* @since 2024/4/18
*/
@Data
@ConfigurationProperties(prefix = "security")
public class SecurityProperties {
/**
* 白名单 URL 集合
*/
private List<String> ignoreUrls;
/**
* JWT 配置
*/
private JwtProperty jwt;
/**
* JWT 配置
*/
@Data
public static class JwtProperty {
/**
* JWT 秘钥
*/
private String key;
/**
* JWT 过期时间
*/
private Long ttl;
}
}
......@@ -24,7 +24,7 @@ import java.io.IOException;
*/
public class CaptchaValidationFilter extends OncePerRequestFilter {
private static final AntPathRequestMatcher LOGIN_PATH_REQUEST_MATCHER = new AntPathRequestMatcher(com.youlai.system.security.constant.SecurityConstants.LOGIN_PATH, "POST");
private static final AntPathRequestMatcher LOGIN_PATH_REQUEST_MATCHER = new AntPathRequestMatcher(SecurityConstants.LOGIN_PATH, "POST");
public static final String CAPTCHA_CODE_PARAM_NAME = "captchaCode";
public static final String CAPTCHA_KEY_PARAM_NAME = "captchaKey";
......
package com.youlai.system.filter;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTUtil;
import com.youlai.system.common.constant.SecurityConstants;
import com.youlai.system.common.result.ResultCode;
import com.youlai.system.security.util.JwtUtils;
import com.youlai.system.common.util.ResponseUtils;
import com.youlai.system.common.exception.BusinessException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
......@@ -19,22 +20,25 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.Map;
/**
* JWT token 校验过滤器
*
* @author haoxr
* @author Ray Hao
* @since 2023/9/13
*/
public class JwtValidationFilter extends OncePerRequestFilter {
private final RedisTemplate<String, Object> redisTemplate;
public JwtValidationFilter(RedisTemplate<String, Object> redisTemplate) {
private final byte[] secretKey;
public JwtValidationFilter(RedisTemplate<String, Object> redisTemplate, String secretKey) {
this.redisTemplate = redisTemplate;
this.secretKey = secretKey.getBytes();
}
/**
* 从请求中获取 JWT Token,校验 JWT Token 是否合法
* <p>
......@@ -44,27 +48,38 @@ public class JwtValidationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String token = request.getHeader(HttpHeaders.AUTHORIZATION);
try {
if (StrUtil.isNotBlank(token)) {
Map<String, Object> payload = JwtUtils.parseToken(token);
if (StrUtil.isNotBlank(token) && token.startsWith(SecurityConstants.JWT_TOKEN_PREFIX)) {
token = token.substring(SecurityConstants.JWT_TOKEN_PREFIX.length()); // 去除 Bearer 前缀
// 校验 Token 是否有效
if (JWTUtil.verify(token, secretKey)) {
// 解析 Token 获取有效载荷
JWT jwt = JWTUtil.parseToken(token);
JSONObject payloads = jwt.getPayloads();
String jti = Convert.toStr(payload.get(JWTPayload.JWT_ID));
Boolean isTokenBlacklisted = redisTemplate.hasKey(SecurityConstants.BLACKLIST_TOKEN_PREFIX + jti);
if (Boolean.TRUE.equals(isTokenBlacklisted)) {
// 检查 Token 是否已被加入黑名单
String jti = payloads.getStr(JWTPayload.JWT_ID);
boolean isTokenBlacklisted = Boolean.TRUE.equals(redisTemplate.hasKey(SecurityConstants.BLACKLIST_TOKEN_PREFIX + jti));
if (isTokenBlacklisted) {
ResponseUtils.writeErrMsg(response, ResultCode.TOKEN_INVALID);
return;
}
// Token 有效将其解析为 Authentication 对象,并设置到 Spring Security 上下文中
Authentication authentication = JwtUtils.getAuthentication(payloads);
SecurityContextHolder.getContext().setAuthentication(authentication);
} else {
// Token 无效,直接返回响应
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
} catch (Exception e) {
SecurityContextHolder.clearContext();
ResponseUtils.writeErrMsg(response, (ResultCode) ex.getResultCode());
ResponseUtils.writeErrMsg(response, ResultCode.TOKEN_INVALID);
return;
}
// Token有效或无Token时继续执行过滤链
filterChain.doFilter(request, response);
}
}
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 cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.RegisteredPayload;
import com.youlai.system.common.constant.SecurityConstants;
import com.youlai.system.common.exception.BusinessException;
import com.youlai.system.security.util.JwtUtils;
import com.youlai.system.common.result.ResultCode;
import com.youlai.system.plugin.dupsubmit.annotation.PreventDuplicateSubmit;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
......@@ -69,8 +70,10 @@ public class DuplicateSubmitAspect {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader(HttpHeaders.AUTHORIZATION);
if (StrUtil.isNotBlank(token)) {
String jti = Convert.toStr(JwtUtils.parseToken(token).get("jti"), null);
if (StrUtil.isNotBlank(token) && token.startsWith(SecurityConstants.JWT_TOKEN_PREFIX)) {
token = token.substring(SecurityConstants.JWT_TOKEN_PREFIX.length());
// 从 JWT Token 中获取 jti
String jti = (String) JWTUtil.parseToken(token).getPayload(RegisteredPayload.JWT_ID);
resubmitLockKey = RESUBMIT_LOCK_PREFIX + jti + ":" + request.getMethod() + "-" + request.getRequestURI();
}
return resubmitLockKey;
......
package com.youlai.system.security.constant;
/**
* Security 常量
*
* @author haoxr
* @since 2.0.0
*/
public interface SecurityConstants {
/**
* 登录接口路径
*/
String LOGIN_PATH = "/api/v1/auth/login";
}
......@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.youlai.system.model.dto.UserAuthInfo;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
......@@ -24,6 +25,7 @@ import java.util.stream.Collectors;
@NoArgsConstructor
public class SysUserDetails implements UserDetails {
@Getter
private Long userId;
private String username;
......@@ -60,10 +62,6 @@ public class SysUserDetails implements UserDetails {
this.dataScope = user.getDataScope();
}
public Long getUserId() {
return this.userId;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
......
......@@ -3,12 +3,10 @@ package com.youlai.system.security.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.json.JSONObject;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTUtil;
import com.youlai.system.security.constant.JwtClaimConstants;
import com.youlai.system.common.constant.JwtClaimConstants;
import com.youlai.system.security.model.SysUserDetails;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
......@@ -21,9 +19,9 @@ import java.util.*;
import java.util.stream.Collectors;
/**
* JWT 工具类
* JWT Token 工具类
*
* @author haoxr
* @author Ray Hao
* @since 2.6.0
*/
@Component
......@@ -41,12 +39,12 @@ public class JwtUtils {
private static int ttl;
@Value("${jwt.key}")
@Value("${security.jwt.key}")
public void setKey(String key) {
JwtUtils.key = key.getBytes();
}
@Value("${jwt.ttl}")
@Value("${security.jwt.ttl}")
public void setTtl(Integer ttl) {
JwtUtils.ttl = ttl;
}
......@@ -57,7 +55,7 @@ public class JwtUtils {
* @param authentication 用户认证信息
* @return Token 字符串
*/
public static String generateToken(Authentication authentication) {
public static String createToken(Authentication authentication) {
SysUserDetails userDetails = (SysUserDetails) authentication.getPrincipal();
......@@ -80,25 +78,25 @@ public class JwtUtils {
payload.put(JWTPayload.SUBJECT, authentication.getName());
payload.put(JWTPayload.JWT_ID, IdUtil.simpleUUID());
return JWTUtil.createToken(payload, JwtUtils.key);
return JWTUtil.createToken(payload, key);
}
/**
* 从 JWT Token 中解析 Authentication 用户认证信息
*
* @param payload JWT 载体
* @param payloads JWT 载体
* @return 用户认证信息
*/
public static UsernamePasswordAuthenticationToken getAuthentication(Map<String, Object> payload) {
public static UsernamePasswordAuthenticationToken getAuthentication(JSONObject payloads) {
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.setUserId(payloads.getLong(JwtClaimConstants.USER_ID)); // 用户ID
userDetails.setDeptId(payloads.getLong(JwtClaimConstants.DEPT_ID)); // 部门ID
userDetails.setDataScope(payloads.getInt(JwtClaimConstants.DATA_SCOPE)); // 数据权限范围
userDetails.setUsername(Convert.toStr(payload.get(JWTPayload.SUBJECT))); // 用户名
userDetails.setUsername(payloads.getStr(JWTPayload.SUBJECT)); // 用户名
// 角色集合
Set<SimpleGrantedAuthority> authorities = ((JSONArray) payload.get(JwtClaimConstants.AUTHORITIES))
Set<SimpleGrantedAuthority> authorities = payloads.getJSONArray(JwtClaimConstants.AUTHORITIES)
.stream()
.map(authority -> new SimpleGrantedAuthority(Convert.toStr(authority)))
.collect(Collectors.toSet());
......@@ -107,30 +105,4 @@ public class JwtUtils {
}
/**
* 解析 JWT 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;
}
}
......@@ -3,10 +3,11 @@ 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.json.JSONObject;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTUtil;
import com.youlai.system.common.constant.SecurityConstants;
import com.youlai.system.common.enums.CaptchaTypeEnum;
import com.youlai.system.model.dto.CaptchaResult;
......@@ -28,7 +29,6 @@ import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.awt.*;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
......@@ -43,7 +43,7 @@ import java.util.concurrent.TimeUnit;
public class AuthServiceImpl implements AuthService {
private final AuthenticationManager authenticationManager;
private final RedisTemplate<String,Object> redisTemplate;
private final RedisTemplate<String, Object> redisTemplate;
private final CodeGenerator codeGenerator;
private final Font captchaFont;
private final CaptchaProperties captchaProperties;
......@@ -57,10 +57,13 @@ public class AuthServiceImpl implements AuthService {
*/
@Override
public LoginResult login(String username, String password) {
// 认证用户信息
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(username.toLowerCase().trim(), password);
// 认证
Authentication authentication = authenticationManager.authenticate(authenticationToken);
String accessToken = JwtUtils.generateToken(authentication);
// 认证成功,生成Token
String accessToken = JwtUtils.createToken(authentication);
return LoginResult.builder()
.tokenType("Bearer")
.accessToken(accessToken)
......@@ -74,18 +77,24 @@ public class AuthServiceImpl implements AuthService {
public void logout() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader(HttpHeaders.AUTHORIZATION);
if (StrUtil.isNotBlank(token)) {
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 (StrUtil.isNotBlank(token) && token.startsWith(SecurityConstants.JWT_TOKEN_PREFIX)) {
token = token.substring(SecurityConstants.JWT_TOKEN_PREFIX.length());
// 解析Token以获取有效载荷(payload)
JSONObject payloads = JWTUtil.parseToken(token).getPayloads();
// 解析 Token 获取 jti(JWT ID) 和 exp(过期时间)
String jti = payloads.getStr(JWTPayload.JWT_ID);
Long expiration = payloads.getLong(JWTPayload.EXPIRES_AT);
// 如果exp存在,则计算Token剩余有效时间
if (expiration != null) {
// 将Token的jti加入黑名单,并设置剩余有效时间,使其在过期后自动从黑名单移除
long ttl = expiration - System.currentTimeMillis() / 1000;
redisTemplate.opsForValue().set(SecurityConstants.BLACKLIST_TOKEN_PREFIX + jti, null, ttl, TimeUnit.SECONDS);
} else {
// 如果exp不存在,说明Token永不过期,则永久加入黑名单
redisTemplate.opsForValue().set(SecurityConstants.BLACKLIST_TOKEN_PREFIX + jti, null);
}
}
// 清空Spring Security上下文
SecurityContextHolder.clearContext();
}
......
......@@ -57,12 +57,21 @@ mybatis-plus:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 认证配置
jwt:
# 密钥
key: SecretKey012345678901234567890123456789012345678901234567890123456789
# token 过期时间(单位:秒)
ttl: 7200
# 安全配置
security:
jwt:
key: SecretKey012345678901234567890123456789012345678901234567890123456789
ttl: 7200
ignore-urls:
- /v3/api-docs/**
- /doc.html
- /swagger-resources/**
- /webjars/**
- /doc.html
- /swagger-ui/**
- /swagger-ui.html
- /api/v1/auth/captcha
oss:
# OSS 类型 (目前支持aliyun、minio)
......
......@@ -57,13 +57,22 @@ mybatis-plus:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 认证配置
jwt:
# 密钥
key: SecretKey012345678901234567890123456789012345678901234567890123456789
# token 过期时间(单位:秒)
ttl: 7200
# 安全配置
security:
jwt:
key: SecretKey012345678901234567890123456789012345678901234567890123456789
ttl: 7200
ignore-urls:
- /v3/api-docs/**
- /doc.html
- /swagger-resources/**
- /webjars/**
- /doc.html
- /swagger-ui/**
- /swagger-ui.html
- /api/v1/auth/captcha
# 文件上传配置
oss:
# OSS 类型 (目前支持aliyun、minio)
type: minio
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册