refactor: 拆分多租户
This commit is contained in:
@@ -7,7 +7,7 @@ import cn.hutool.json.JSONUtil;
|
||||
import com.youlai.boot.common.constant.RedisConstants;
|
||||
import com.youlai.boot.common.constant.SecurityConstants;
|
||||
import com.youlai.boot.core.web.ResultCode;
|
||||
import com.youlai.boot.core.web.WebResponseHelper;
|
||||
import com.youlai.boot.core.web.WebResponseWriter;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.ServletInputStream;
|
||||
@@ -61,7 +61,7 @@ public class CaptchaValidationFilter extends OncePerRequestFilter {
|
||||
// 仅支持 JSON 登录
|
||||
String contentType = request.getContentType();
|
||||
if (contentType == null || !contentType.contains(MediaType.APPLICATION_JSON_VALUE)) {
|
||||
WebResponseHelper.writeError(response, ResultCode.USER_VERIFICATION_CODE_ERROR);
|
||||
WebResponseWriter.writeError(response, ResultCode.USER_VERIFICATION_CODE_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ public class CaptchaValidationFilter extends OncePerRequestFilter {
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(captchaCode) || StrUtil.isBlank(captchaId)) {
|
||||
WebResponseHelper.writeError(response, ResultCode.USER_VERIFICATION_CODE_ERROR);
|
||||
WebResponseWriter.writeError(response, ResultCode.USER_VERIFICATION_CODE_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ public class CaptchaValidationFilter extends OncePerRequestFilter {
|
||||
StrUtil.format(RedisConstants.Captcha.IMAGE_CODE, captchaId)
|
||||
);
|
||||
if (cacheVerifyCode == null) {
|
||||
WebResponseHelper.writeError(response, ResultCode.USER_VERIFICATION_CODE_EXPIRED);
|
||||
WebResponseWriter.writeError(response, ResultCode.USER_VERIFICATION_CODE_EXPIRED);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ public class CaptchaValidationFilter extends OncePerRequestFilter {
|
||||
HttpServletRequest repeatableRequest = new RepeatableReadRequestWrapper(requestWrapper, bodyBytes);
|
||||
chain.doFilter(repeatableRequest, response);
|
||||
} else {
|
||||
WebResponseHelper.writeError(response, ResultCode.USER_VERIFICATION_CODE_ERROR);
|
||||
WebResponseWriter.writeError(response, ResultCode.USER_VERIFICATION_CODE_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.youlai.boot.security.filter;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.youlai.boot.common.constant.SecurityConstants;
|
||||
import com.youlai.boot.core.web.ResultCode;
|
||||
import com.youlai.boot.core.web.WebResponseHelper;
|
||||
import com.youlai.boot.core.web.WebResponseWriter;
|
||||
import com.youlai.boot.security.token.TokenManager;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
@@ -52,7 +52,7 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
||||
// 执行令牌有效性检查(包含密码学验签和过期时间验证)
|
||||
boolean isValidToken = tokenManager.validateToken(rawToken);
|
||||
if (!isValidToken) {
|
||||
WebResponseHelper.writeError(response, ResultCode.ACCESS_TOKEN_INVALID);
|
||||
WebResponseWriter.writeError(response, ResultCode.ACCESS_TOKEN_INVALID);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
||||
} catch (Exception ex) {
|
||||
// 安全上下文清除保障(防止上下文残留)
|
||||
SecurityContextHolder.clearContext();
|
||||
WebResponseHelper.writeError(response, ResultCode.ACCESS_TOKEN_INVALID);
|
||||
WebResponseWriter.writeError(response, ResultCode.ACCESS_TOKEN_INVALID);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.youlai.boot.security.handler;
|
||||
|
||||
import com.youlai.boot.core.web.ResultCode;
|
||||
import com.youlai.boot.core.web.WebResponseHelper;
|
||||
import com.youlai.boot.core.web.WebResponseWriter;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -20,7 +20,7 @@ public class MyAccessDeniedHandler implements AccessDeniedHandler {
|
||||
|
||||
@Override
|
||||
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) {
|
||||
WebResponseHelper.writeError(response, ResultCode.ACCESS_UNAUTHORIZED);
|
||||
WebResponseWriter.writeError(response, ResultCode.ACCESS_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.youlai.boot.security.handler;
|
||||
|
||||
import com.youlai.boot.core.web.ResultCode;
|
||||
import com.youlai.boot.core.web.WebResponseHelper;
|
||||
import com.youlai.boot.core.web.WebResponseWriter;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.InsufficientAuthenticationException;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
@@ -32,13 +32,13 @@ public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
|
||||
if (authException instanceof BadCredentialsException) {
|
||||
// 用户名或密码错误
|
||||
WebResponseHelper.writeError(response, ResultCode.USER_PASSWORD_ERROR);
|
||||
WebResponseWriter.writeError(response, ResultCode.USER_PASSWORD_ERROR);
|
||||
} else if(authException instanceof InsufficientAuthenticationException){
|
||||
// 请求头缺失Authorization、Token格式错误、Token过期、签名验证失败
|
||||
WebResponseHelper.writeError(response, ResultCode.ACCESS_TOKEN_INVALID);
|
||||
WebResponseWriter.writeError(response, ResultCode.ACCESS_TOKEN_INVALID);
|
||||
} else {
|
||||
// 其他未明确处理的认证异常(如账户被锁定、账户禁用等)
|
||||
WebResponseHelper.writeError(response, ResultCode.USER_LOGIN_EXCEPTION, authException.getMessage());
|
||||
WebResponseWriter.writeError(response, ResultCode.USER_LOGIN_EXCEPTION, authException.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,11 +38,6 @@ public class OnlineUser {
|
||||
*/
|
||||
private Integer dataScope;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 角色权限集合
|
||||
*/
|
||||
|
||||
@@ -56,11 +56,6 @@ public class SysUserDetails implements UserDetails {
|
||||
*/
|
||||
private Integer dataScope;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 用户角色权限集合
|
||||
*/
|
||||
@@ -78,7 +73,6 @@ public class SysUserDetails implements UserDetails {
|
||||
this.enabled = ObjectUtil.equal(user.getStatus(), 1);
|
||||
this.deptId = user.getDeptId();
|
||||
this.dataScope = user.getDataScope();
|
||||
this.tenantId = user.getTenantId();
|
||||
|
||||
// 初始化角色权限集合
|
||||
this.authorities = CollectionUtil.isNotEmpty(user.getRoles())
|
||||
|
||||
@@ -54,9 +54,4 @@ public class UserAuthCredentials {
|
||||
*/
|
||||
private Integer dataScope;
|
||||
|
||||
/**
|
||||
* 租户ID(从登录上下文中获取)
|
||||
*/
|
||||
private Long tenantId;
|
||||
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@ package com.youlai.boot.security.service;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.youlai.boot.common.constant.RedisConstants;
|
||||
import com.youlai.boot.common.tenant.TenantContextHolder;
|
||||
import com.youlai.boot.config.property.TenantProperties;
|
||||
import com.youlai.boot.security.util.SecurityUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -26,7 +24,6 @@ import java.util.*;
|
||||
public class PermissionService {
|
||||
|
||||
private final RedisTemplate<String, Object> redisTemplate;
|
||||
private final TenantProperties tenantProperties;
|
||||
|
||||
/**
|
||||
* 判断当前登录用户是否拥有操作权限
|
||||
@@ -70,20 +67,7 @@ public class PermissionService {
|
||||
|
||||
|
||||
/**
|
||||
* 构建租户权限缓存key
|
||||
*
|
||||
* @param tenantId 租户ID
|
||||
* @return 缓存key
|
||||
*/
|
||||
private String buildRolePermsCacheKey(Long tenantId) {
|
||||
if (!tenantProperties.getEnabled() || tenantId == null) {
|
||||
return RedisConstants.System.ROLE_PERMS;
|
||||
}
|
||||
return RedisConstants.System.ROLE_PERMS + ":" + tenantId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存中获取角色权限列表(兼容单租户和多租户)
|
||||
* 从缓存中获取角色权限列表
|
||||
*
|
||||
* @param roleCodes 角色编码集合
|
||||
* @return 角色权限列表
|
||||
@@ -93,9 +77,8 @@ public class PermissionService {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
// 获取当前租户ID并构建缓存Key
|
||||
Long tenantId = TenantContextHolder.getTenantId();
|
||||
String cacheKey = buildRolePermsCacheKey(tenantId);
|
||||
// 构建缓存Key
|
||||
String cacheKey = RedisConstants.System.ROLE_PERMS;
|
||||
|
||||
Set<String> perms = new HashSet<>();
|
||||
Collection<Object> roleCodesAsObjects = new ArrayList<>(roleCodes);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.youlai.boot.security.service;
|
||||
|
||||
import com.youlai.boot.common.tenant.TenantContextHolder;
|
||||
import com.youlai.boot.security.model.SysUserDetails;
|
||||
import com.youlai.boot.security.model.UserAuthCredentials;
|
||||
import com.youlai.boot.system.service.UserService;
|
||||
@@ -38,8 +37,6 @@ public class SysUserDetailsService implements UserDetailsService {
|
||||
if (userAuthCredentials == null) {
|
||||
throw new UsernameNotFoundException(username);
|
||||
}
|
||||
// 将当前上下文中的租户ID写入认证凭证,便于后续 Token 携带租户信息
|
||||
userAuthCredentials.setTenantId(TenantContextHolder.getTenantId());
|
||||
return new SysUserDetails(userAuthCredentials);
|
||||
} catch (Exception e) {
|
||||
// 记录异常日志
|
||||
|
||||
@@ -91,7 +91,6 @@ public class JwtTokenManager implements TokenManager {
|
||||
userDetails.setUserId(payloads.getLong(JwtClaimConstants.USER_ID)); // 用户ID
|
||||
userDetails.setDeptId(payloads.getLong(JwtClaimConstants.DEPT_ID)); // 部门ID
|
||||
userDetails.setDataScope(payloads.getInt(JwtClaimConstants.DATA_SCOPE)); // 数据权限范围
|
||||
userDetails.setTenantId(payloads.getLong(JwtClaimConstants.TENANT_ID)); // 租户ID
|
||||
|
||||
userDetails.setUsername(payloads.getStr(JWTPayload.SUBJECT)); // 用户名
|
||||
// 角色集合
|
||||
@@ -276,7 +275,6 @@ public class JwtTokenManager implements TokenManager {
|
||||
payload.put(JwtClaimConstants.USER_ID, userDetails.getUserId()); // 用户ID
|
||||
payload.put(JwtClaimConstants.DEPT_ID, userDetails.getDeptId()); // 部门ID
|
||||
payload.put(JwtClaimConstants.DATA_SCOPE, userDetails.getDataScope()); // 数据权限范围
|
||||
payload.put(JwtClaimConstants.TENANT_ID, userDetails.getTenantId()); // 租户ID
|
||||
|
||||
// claims 中添加角色信息
|
||||
Set<String> roles = authentication.getAuthorities().stream()
|
||||
|
||||
@@ -61,7 +61,6 @@ public class RedisTokenManager implements TokenManager {
|
||||
user.getUsername(),
|
||||
user.getDeptId(),
|
||||
user.getDataScope(),
|
||||
user.getTenantId(),
|
||||
user.getAuthorities().stream()
|
||||
.map(GrantedAuthority::getAuthority)
|
||||
.collect(Collectors.toSet())
|
||||
@@ -269,7 +268,6 @@ public class RedisTokenManager implements TokenManager {
|
||||
userDetails.setUsername(onlineUser.getUsername());
|
||||
userDetails.setDeptId(onlineUser.getDeptId());
|
||||
userDetails.setDataScope(onlineUser.getDataScope());
|
||||
userDetails.setTenantId(onlineUser.getTenantId());
|
||||
userDetails.setAuthorities(authorities);
|
||||
return userDetails;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user