Merge branch 'master' of gitee.com:youlaiorg/youlai-boot into tkyj-jwt
Signed-off-by: 太空眼睛 <best5721@sina.com>
This commit is contained in:
@@ -7,18 +7,18 @@ import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.youlai.boot.auth.enums.CaptchaTypeEnum;
|
||||
import com.youlai.boot.auth.model.CaptchaInfo;
|
||||
import com.youlai.boot.auth.model.dto.WxMiniAppCodeLoginDTO;
|
||||
import com.youlai.boot.auth.model.dto.WxMiniAppPhoneLoginDTO;
|
||||
import com.youlai.boot.auth.service.AuthService;
|
||||
import com.youlai.boot.common.constant.RedisConstants;
|
||||
import com.youlai.boot.common.constant.SecurityConstants;
|
||||
import com.youlai.boot.common.exception.BusinessException;
|
||||
import com.youlai.boot.common.result.ResultCode;
|
||||
import com.youlai.boot.config.property.CaptchaProperties;
|
||||
import com.youlai.boot.core.security.extension.sms.SmsAuthenticationToken;
|
||||
import com.youlai.boot.core.security.util.SecurityUtils;
|
||||
import com.youlai.boot.core.security.extension.wx.WxMiniAppCodeAuthenticationToken;
|
||||
import com.youlai.boot.core.security.extension.wx.WxMiniAppPhoneAuthenticationToken;
|
||||
import com.youlai.boot.core.security.model.AuthenticationToken;
|
||||
import com.youlai.boot.auth.model.dto.WxMiniAppCodeLoginDTO;
|
||||
import com.youlai.boot.auth.service.AuthService;
|
||||
import com.youlai.boot.core.security.token.TokenManager;
|
||||
import com.youlai.boot.core.security.util.SecurityUtils;
|
||||
import com.youlai.boot.shared.sms.enums.SmsTypeEnum;
|
||||
import com.youlai.boot.shared.sms.service.SmsService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -29,8 +29,6 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.youlai.boot.core.security.extension.wx.WxMiniAppCodeAuthenticationToken;
|
||||
import com.youlai.boot.core.security.extension.wx.WxMiniAppPhoneAuthenticationToken;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.HashMap;
|
||||
@@ -220,13 +218,6 @@ public class AuthServiceImpl implements AuthService {
|
||||
*/
|
||||
@Override
|
||||
public AuthenticationToken refreshToken(String refreshToken) {
|
||||
// 验证刷新令牌
|
||||
boolean isValidate = tokenManager.validateRefreshToken(refreshToken);
|
||||
|
||||
if (!isValidate) {
|
||||
throw new BusinessException(ResultCode.REFRESH_TOKEN_INVALID);
|
||||
}
|
||||
// 刷新令牌有效,生成新的访问令牌
|
||||
return tokenManager.refreshToken(refreshToken);
|
||||
}
|
||||
|
||||
@@ -265,14 +256,14 @@ public class AuthServiceImpl implements AuthService {
|
||||
loginDTO.getEncryptedData(),
|
||||
loginDTO.getIv()
|
||||
);
|
||||
|
||||
|
||||
// 执行认证
|
||||
Authentication authentication = authenticationManager.authenticate(authenticationToken);
|
||||
|
||||
|
||||
// 认证成功后生成JWT令牌,并存入Security上下文
|
||||
AuthenticationToken token = tokenManager.generateToken(authentication);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,11 @@ package com.youlai.boot.common.constant;
|
||||
*/
|
||||
public interface JwtClaimConstants {
|
||||
|
||||
/**
|
||||
* 令牌类型
|
||||
*/
|
||||
String TOKEN_TYPE = "tokenType";
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
|
||||
@@ -14,9 +14,9 @@ import com.youlai.boot.common.constant.SecurityConstants;
|
||||
import com.youlai.boot.common.exception.BusinessException;
|
||||
import com.youlai.boot.common.result.ResultCode;
|
||||
import com.youlai.boot.config.property.SecurityProperties;
|
||||
import com.youlai.boot.core.security.model.SysUserDetails;
|
||||
import com.youlai.boot.core.security.model.AuthenticationToken;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import com.youlai.boot.core.security.model.SysUserDetails;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
@@ -66,7 +66,7 @@ public class JwtTokenManager implements TokenManager {
|
||||
int refreshTokenTimeToLive = securityProperties.getSession().getRefreshTokenTimeToLive();
|
||||
|
||||
String accessToken = generateToken(authentication, accessTokenTimeToLive);
|
||||
String refreshToken = generateToken(authentication, refreshTokenTimeToLive);
|
||||
String refreshToken = generateToken(authentication, refreshTokenTimeToLive, true);
|
||||
|
||||
return AuthenticationToken.builder()
|
||||
.accessToken(accessToken)
|
||||
@@ -110,26 +110,54 @@ public class JwtTokenManager implements TokenManager {
|
||||
*/
|
||||
@Override
|
||||
public boolean validateToken(String token) {
|
||||
JWT jwt = JWTUtil.parseToken(token);
|
||||
// 检查 Token 是否有效(验签 + 是否过期)
|
||||
boolean isValid = jwt.setKey(secretKey).validate(0);
|
||||
|
||||
if (isValid) {
|
||||
// 检查 Token 是否已被加入黑名单(注销、修改密码等场景)
|
||||
JSONObject payloads = jwt.getPayloads();
|
||||
String jti = payloads.getStr(JWTPayload.JWT_ID);
|
||||
|
||||
// 判断是否在黑名单中,如果在,则返回 false 标识Token无效
|
||||
if (Boolean.TRUE.equals(redisTemplate.hasKey(StrUtil.format(RedisConstants.Auth.BLACKLIST_TOKEN, jti)))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return isValid;
|
||||
return validateToken(token,false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验刷新令牌
|
||||
*
|
||||
* @param refreshToken JWT Token
|
||||
* @return 验证结果
|
||||
*/
|
||||
@Override
|
||||
public boolean validateRefreshToken(String refreshToken) {
|
||||
return this.validateToken(refreshToken);
|
||||
return validateToken(refreshToken,true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验令牌
|
||||
*
|
||||
* @param token JWT Token
|
||||
* @param validateRefreshToken 是否校验刷新令牌
|
||||
* @return 是否有效
|
||||
*/
|
||||
private boolean validateToken(String token, boolean validateRefreshToken) {
|
||||
try {
|
||||
JWT jwt = JWTUtil.parseToken(token);
|
||||
// 检查 Token 是否有效(验签 + 是否过期)
|
||||
boolean isValid = jwt.setKey(secretKey).validate(0);
|
||||
|
||||
if (isValid) {
|
||||
// 检查 Token 是否已被加入黑名单(注销、修改密码等场景)
|
||||
JSONObject payloads = jwt.getPayloads();
|
||||
String jti = payloads.getStr(JWTPayload.JWT_ID);
|
||||
if(validateRefreshToken) {
|
||||
//刷新token需要校验token类别
|
||||
boolean isRefreshToken = payloads.getBool(JwtClaimConstants.TOKEN_TYPE);
|
||||
if (!isRefreshToken) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 判断是否在黑名单中,如果在,则返回 false 标识Token无效
|
||||
if (Boolean.TRUE.equals(redisTemplate.hasKey(StrUtil.format(RedisConstants.Auth.BLACKLIST_TOKEN, jti)))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return isValid;
|
||||
} catch (Exception gitignore) {
|
||||
// token 验证
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,12 +174,9 @@ public class JwtTokenManager implements TokenManager {
|
||||
if (token.startsWith(SecurityConstants.BEARER_TOKEN_PREFIX)) {
|
||||
token = token.substring(SecurityConstants.BEARER_TOKEN_PREFIX.length());
|
||||
}
|
||||
|
||||
JWT jwt = JWTUtil.parseToken(token);
|
||||
JSONObject payloads = jwt.getPayloads();
|
||||
|
||||
Integer expirationAt = payloads.getInt(JWTPayload.EXPIRES_AT);
|
||||
|
||||
// 黑名单Token Key
|
||||
String blacklistTokenKey = StrUtil.format(RedisConstants.Auth.BLACKLIST_TOKEN, payloads.getStr(JWTPayload.JWT_ID));
|
||||
|
||||
@@ -179,16 +204,13 @@ public class JwtTokenManager implements TokenManager {
|
||||
*/
|
||||
@Override
|
||||
public AuthenticationToken refreshToken(String refreshToken) {
|
||||
|
||||
boolean isValid = validateToken(refreshToken);
|
||||
boolean isValid = validateRefreshToken(refreshToken);
|
||||
if (!isValid) {
|
||||
throw new BusinessException(ResultCode.REFRESH_TOKEN_INVALID);
|
||||
}
|
||||
|
||||
Authentication authentication = parseToken(refreshToken);
|
||||
int accessTokenExpiration = securityProperties.getSession().getAccessTokenTimeToLive();
|
||||
String newAccessToken = generateToken(authentication, accessTokenExpiration);
|
||||
|
||||
return AuthenticationToken.builder()
|
||||
.accessToken(newAccessToken)
|
||||
.refreshToken(refreshToken)
|
||||
@@ -201,13 +223,24 @@ public class JwtTokenManager implements TokenManager {
|
||||
* 生成 JWT Token
|
||||
*
|
||||
* @param authentication 认证信息
|
||||
* @param ttl 过期时间
|
||||
* @param ttl 过期时间
|
||||
* @return JWT Token
|
||||
*/
|
||||
private String generateToken(Authentication authentication, int ttl) {
|
||||
return generateToken(authentication, ttl, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成 JWT Token
|
||||
*
|
||||
* @param authentication 认证信息
|
||||
* @param ttl 过期时间
|
||||
* @param isRefreshToken 类型是否为刷新token
|
||||
* @return JWT Token
|
||||
*/
|
||||
private String generateToken(Authentication authentication, int ttl, boolean isRefreshToken) {
|
||||
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
|
||||
@@ -221,6 +254,10 @@ public class JwtTokenManager implements TokenManager {
|
||||
|
||||
Date now = new Date();
|
||||
payload.put(JWTPayload.ISSUED_AT, now);
|
||||
payload.put(JwtClaimConstants.TOKEN_TYPE, false);
|
||||
if (isRefreshToken) {
|
||||
payload.put(JwtClaimConstants.TOKEN_TYPE, true);
|
||||
}
|
||||
|
||||
// 设置过期时间 -1 表示永不过期
|
||||
if (ttl != -1) {
|
||||
@@ -232,4 +269,5 @@ public class JwtTokenManager implements TokenManager {
|
||||
|
||||
return JWTUtil.createToken(payload, secretKey);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@ public class MenuController {
|
||||
|
||||
@Operation(summary = "修改菜单显示状态")
|
||||
@PatchMapping("/{menuId}")
|
||||
@PreAuthorize("@ss.hasPerm('sys:menu:edit')")
|
||||
public Result<?> updateMenuVisible(
|
||||
@Parameter(description = "菜单ID") @PathVariable Long menuId,
|
||||
@Parameter(description = "显示状态(1:显示;0:隐藏)") Integer visible
|
||||
|
||||
@@ -91,6 +91,7 @@ public class RoleController {
|
||||
|
||||
@Operation(summary = "修改角色状态")
|
||||
@PutMapping(value = "/{roleId}/status")
|
||||
@PreAuthorize("@ss.hasPerm('sys:role:edit')")
|
||||
public Result<?> updateRoleStatus(
|
||||
@Parameter(description = "角色ID") @PathVariable Long roleId,
|
||||
@Parameter(description = "状态(1:启用;0:禁用)") @RequestParam Integer status
|
||||
|
||||
@@ -80,6 +80,7 @@ public class UserController {
|
||||
|
||||
@Operation(summary = "获取用户表单数据")
|
||||
@GetMapping("/{userId}/form")
|
||||
@PreAuthorize("@ss.hasPerm('sys:user:edit')")
|
||||
@Log(value = "用户表单数据", module = LogModuleEnum.USER)
|
||||
public Result<UserForm> getUserForm(
|
||||
@Parameter(description = "用户ID") @PathVariable Long userId
|
||||
@@ -113,6 +114,7 @@ public class UserController {
|
||||
|
||||
@Operation(summary = "修改用户状态")
|
||||
@PatchMapping(value = "/{userId}/status")
|
||||
@PreAuthorize("@ss.hasPerm('sys:user:edit')")
|
||||
@Log(value = "修改用户状态", module = LogModuleEnum.USER)
|
||||
public Result<Void> updateUserStatus(
|
||||
@Parameter(description = "用户ID") @PathVariable Long userId,
|
||||
|
||||
Reference in New Issue
Block a user