初始化项目

This commit is contained in:
2026-04-21 16:12:04 +08:00
parent 4541af2c63
commit f9d96473da
443 changed files with 36365 additions and 19 deletions

View File

@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.xujun</groupId>
<artifactId>xtools-app-sys</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>xtools-app-sys-auth</artifactId>
<!-- 依赖 -->
<dependencies>
<!-- xtools begin -->
<!-- xtools-web 模块 -->
<dependency>
<groupId>org.xujun</groupId>
<artifactId>xtools-web</artifactId>
</dependency>
<!-- xtools-boot-base -->
<dependency>
<groupId>org.xujun</groupId>
<artifactId>xtools-boot-core</artifactId>
</dependency>
<!-- xtools-boot-cache-redis -->
<dependency>
<groupId>org.xujun</groupId>
<artifactId>xtools-boot-cache-redis</artifactId>
</dependency>
<!-- xtools-boot-mask -->
<dependency>
<groupId>org.xujun</groupId>
<artifactId>xtools-boot-mask</artifactId>
</dependency>
<!-- xtools-boot-web-filter -->
<dependency>
<groupId>org.xujun</groupId>
<artifactId>xtools-boot-web-filter</artifactId>
</dependency>
<!-- xtools end -->
<!-- 项目模块 begin -->
<dependency>
<groupId>org.xujun</groupId>
<artifactId>xtools-app-common-cache</artifactId>
</dependency>
<!-- 项目模块 end -->
<!-- spring begin -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<!-- spring end -->
<!-- fastjson2 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
</dependency>
<!-- servlet-api -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,235 @@
package xtools.app.sys.auth.filter;
import com.alibaba.fastjson2.JSONObject;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.NonNull;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import xtools.app.common.cache.enums.AppCache;
import xtools.app.sys.auth.model.dto.LoginUserDto;
import xtools.app.sys.auth.utils.AuthUtils;
import xtools.app.sys.auth.utils.PremUtils;
import xtools.app.sys.auth.whitelist.AuthWhitelist;
import xtools.base.config.BaseParams;
import xtools.boot.api.constant.BootCommonConstant;
import xtools.boot.api.enums.ResultType;
import xtools.boot.api.model.dto.Result;
import xtools.boot.cache.redis.base.RedisService;
import xtools.boot.core.holder.CommonHolder;
import xtools.boot.core.utils.PathPatternUtils;
import xtools.boot.core.utils.SpringContextUtils;
import xtools.boot.mask.utils.MaskIgnoreUtils;
import xtools.boot.web.filter.base.BaseFilter;
import xtools.core.CollectionUtils;
import xtools.core.StringUtils;
import xtools.web.HeaderUtils;
import xtools.web.HttpServletUtils;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
/**
* <p>Title : AuthFilter</p>
* <p>Description : AuthFilter</p>
* <p>DevelopTools : Idea_x64_v2026.1</p>
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
* <p>Company : org.xujun</p>
*
* @author : XuJun
* @version : 1.0.0
* @date : 2026/1/31 21:18
*/
@Component
public class AuthFilter extends BaseFilter implements Ordered, BaseParams {
/**
* 微服务标识
*/
private static final String CLOUD_FLAG = String.valueOf(Boolean.TRUE);
/**
* 缓存参数
*/
private static final AppCache CACHE_PARAM = AppCache.AUTH_CLOUD_TOKEN;
/**
* 权限白名单
*/
private static final Set<String> AUTH_WHITE_LIST = new HashSet<>();
/**
* 登录白名单
*/
private static final Set<String> LOGIN_WHITE_LIST = new HashSet<>();
@Resource
private RedisService redisService;
@Override
public int getOrder() {
return CP_NUM200 + CP_NUM1;
}
@Override
protected void initFilterBean() throws ServletException {
super.initFilterBean();
Collection<AuthWhitelist> beanList = SpringContextUtils.getBeanList(AuthWhitelist.class);
if (CollectionUtils.isEmpty(beanList)) {
return;
}
beanList.forEach(item -> {
AUTH_WHITE_LIST.addAll(item.addAuth());
LOGIN_WHITE_LIST.addAll(item.addLogin());
});
}
@Override
protected void doFilterInternal(
@NonNull HttpServletRequest request,
@NonNull HttpServletResponse response,
@NonNull FilterChain filterChain
) throws ServletException, IOException {
// 判断是否为微服务请求
if (Objects.equals(HeaderUtils.getHeader(request, BootCommonConstant.CLOUD), CLOUD_FLAG)) {
// 微服务请求
cloudAuth(request, response, filterChain);
} else {
// 常规请求
auth(request, response, filterChain);
}
}
/**
* 微服务验证权限
*
* @param request 请求
* @param response 响应
* @param filterChain 过滤器链
*/
private void cloudAuth(
@NonNull HttpServletRequest request,
@NonNull HttpServletResponse response,
@NonNull FilterChain filterChain
) throws ServletException, IOException {
String token = HeaderUtils.getHeader(request, BootCommonConstant.CLOUD_TOKEN);
if (StringUtils.isBlank(token)) {
HttpServletUtils.respWriter(response, JSONObject.from(new Result<>(ResultType.UNAUTHORIZED, null)));
return;
}
Long total = redisService.hashDelete(CACHE_PARAM.key(), token);
if (Objects.isNull(total) || total < CP_NUM1) {
HttpServletUtils.respWriter(response, JSONObject.from(new Result<>(ResultType.UNAUTHORIZED, null)));
return;
}
// 传递头部信息
String uid = AuthUtils.getUid(request);
String accessToken = AuthUtils.getAccessToken(request);
if (StringUtils.isNotBlank(uid)) {
CommonHolder.set(BootCommonConstant.UID, uid);
}
if (StringUtils.isNotBlank(accessToken)) {
CommonHolder.set(BootCommonConstant.AUTHORIZATION, accessToken);
// 校验忽略掩码
checkIgnoreMask();
}
filterChain.doFilter(request, response);
}
/**
* 常规验证权限
*
* @param request 请求
* @param response 响应
* @param filterChain 过滤器链
*/
private void auth(
@NonNull HttpServletRequest request,
@NonNull HttpServletResponse response,
@NonNull FilterChain filterChain
) throws ServletException, IOException {
// 获取访问 uri
String uri = HeaderUtils.getUri(request);
// 忽略权限校验
if (checkAuthWhiteList(uri)) {
filterChain.doFilter(request, response);
return;
}
// 验证uid
String uid = AuthUtils.getUid(request);
if (StringUtils.isBlank(uid)) {
HttpServletUtils.respWriter(response, JSONObject.from(new Result<>(ResultType.METHOD_NOT_ALLOWED, null)));
return;
}
// 校验登录白名单
if (checkLoginWhiteList(uri)) {
filterChain.doFilter(request, response);
return;
}
// 校验登录权限
String accessToken = AuthUtils.getAccessToken(request);
LoginUserDto loginUser = AuthUtils.get(accessToken);
if (Objects.isNull(loginUser)) {
HttpServletUtils.respWriter(response, JSONObject.from(new Result<>(ResultType.UNAUTHORIZED, null)));
return;
}
// 校验 uri 访问权限
String method = request.getMethod();
if (!PremUtils.checkInterfacePerm(uri, method, loginUser.getRoleIds())) {
HttpServletUtils.respWriter(response, JSONObject.from(new Result<>(ResultType.FORBIDDEN, null)));
return;
}
CommonHolder.set(BootCommonConstant.UID, uid);
CommonHolder.set(BootCommonConstant.AUTHORIZATION, accessToken);
CommonHolder.set(BootCommonConstant.AUTH, loginUser);
// 校验忽略掩码
checkIgnoreMask();
filterChain.doFilter(request, response);
}
/**
* 校验忽略掩码
*/
private void checkIgnoreMask() {
if (AuthUtils.isIgnoreMask()) {
// 忽略脱敏
MaskIgnoreUtils.ignore();
}
}
/**
* 检测权限白名单
*
* @param uri 访问 uri
* @return 是否是白名单
*/
private boolean checkAuthWhiteList(String uri) {
return PathPatternUtils.match(AUTH_WHITE_LIST, uri);
}
/**
* 检测登录白名单
*
* @param uri 请求 uri
* @return 是否是白名单
*/
private boolean checkLoginWhiteList(String uri) {
return PathPatternUtils.match(LOGIN_WHITE_LIST, uri);
}
}

View File

@@ -0,0 +1,45 @@
//package xtools.app.sys.auth.holder;
//
//import xtools.app.sys.auth.model.dto.LoginUserDto;
//import xtools.boot.api.exection.UnauthorizedError;
//
/// **
// * <p>Title : LoginUserHolder</p>
// * <p>Description : LoginUserHolder</p>
// * <p>DevelopTools : Idea_x64_v2026.1</p>
// * <p>DevelopSystem : macOS Sequoia 15.7.5</p>
// * <p>Company : org.xujun</p>
// *
// * @author : XuJun
// * @version : 1.0.0
// * @date : 2026/1/31 21:20
// */
//public class AuthHolder {
//
// /**
// * 登录用户信息
// */
// private static final ScopedValue<LoginUserDto> LOGIN_USER_INFO = ScopedValue.newInstance();
//
// /**
// * 获取登录用户信息 Holder
// *
// * @return 登录用户信息
// */
// public static ScopedValue<LoginUserDto> getScoped() {
// return LOGIN_USER_INFO;
// }
//
// /**
// * 获取登录用户信息
// *
// * @return 登录用户信息
// */
// public static LoginUserDto get() {
// if (!LOGIN_USER_INFO.isBound()) {
// throw new UnauthorizedError();
// }
// return LOGIN_USER_INFO.get();
// }
//
//}

View File

@@ -0,0 +1,36 @@
package xtools.app.sys.auth.model.dto;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* <p>Title : InterfacePermDto</p>
* <p>Description : InterfacePermDto</p>
* <p>DevelopTools : Idea_x64_v2026.1</p>
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
* <p>Company : org.xujun</p>
*
* @author : XuJun
* @version : 1.0.0
* @date : 2026/2/2 15:58
*/
@Data
public class InterfacePermDto implements Serializable {
/**
* 接口地址
*/
private String uri;
/**
* 接口类型
*/
private String type;
/**
* 角色 ID 集合
*/
private List<Long> roleIds;
}

View File

@@ -0,0 +1,51 @@
package xtools.app.sys.auth.model.dto;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* <p>Title : LoginUserDto</p>
* <p>Description : LoginUserDto</p>
* <p>DevelopTools : Idea_x64_v2026.1</p>
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
* <p>Company : org.xujun</p>
*
* @author : XuJun
* @version : 1.0.0
* @date : 2026/1/31 20:40
*/
@Data
public class LoginUserDto implements Serializable {
/**
* 用户 ID
*/
private Long id;
/**
* 账号
*/
private String account;
/**
* 昵称
*/
private String nickname;
/**
* 部门 ID
*/
private Long deptId;
/**
* 角色 ID 集合
*/
private List<Long> roleIds;
/**
* 忽略脱敏时间
*/
private Long ignoreMaskTime;
}

View File

@@ -0,0 +1,39 @@
package xtools.app.sys.auth.model.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
/**
* <p>Title : TokenDto</p>
* <p>Description : TokenDto</p>
* <p>DevelopTools : Idea_x64_v2026.1</p>
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
* <p>Company : org.xujun</p>
*
* @author : XuJun
* @version : 1.0.0
* @date : 2026/1/31 14:43
*/
@Data
public class TokenDto implements Serializable {
/**
* 数据 Token
*/
@Schema(description = "数据 Token", example = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbi")
private String accessToken;
/**
* 刷新 Token
*/
@Schema(description = "刷新 Token", example = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbi")
private String refreshToken;
/**
* 数据 Token过期时间
*/
@Schema(description = "数据 Token过期时间", example = "1675000000000")
private Long expiryTime;
}

View File

@@ -0,0 +1,327 @@
package xtools.app.sys.auth.utils;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import jakarta.servlet.http.HttpServletRequest;
import xtools.app.common.cache.enums.AppCache;
import xtools.app.sys.auth.model.dto.LoginUserDto;
import xtools.app.sys.auth.model.dto.TokenDto;
import xtools.base.config.BaseParams;
import xtools.boot.api.constant.BootCommonConstant;
import xtools.boot.api.exection.BizError;
import xtools.boot.api.exection.UnauthorizedError;
import xtools.boot.cache.redis.base.RedisService;
import xtools.boot.cache.redis.utils.RedisUtils;
import xtools.boot.core.holder.CommonHolder;
import xtools.core.CollectionUtils;
import xtools.core.StringUtils;
import xtools.core.UuidUtils;
import xtools.core.extend.CheckUtils;
import xtools.web.HeaderUtils;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
* <p>Title : AuthUtils</p>
* <p>Description : AuthUtils</p>
* <p>DevelopTools : Idea_x64_v2026.1</p>
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
* <p>Company : org.xujun</p>
*
* @author : XuJun
* @version : 1.0.0
* @date : 2026/1/31 20:44
*/
public class AuthUtils implements BaseParams {
/**
* 缓存参数
*/
private static final AppCache CACHE_PARAM = AppCache.AUTH_SYS_USER;
/**
* accessTokenKey
*/
private static final String ACCESS_TOKEN_KEY = "Authorization";
/**
* accessToken
*/
private static final String ACCESS_TOKEN = "accessToken";
/**
* refreshToken
*/
private static final String REFRESH_TOKEN = "refreshToken";
/**
* user
*/
private static final String USER = "id";
/**
* mask
*/
private static final String MASK = "mask";
/**
* 缓存 KeyMap
*/
private static final Map<String, String> CACHE_KEY;
// 初始化
static {
String key = CACHE_PARAM.key();
CACHE_KEY = new ConcurrentHashMap<>(CP_NUM16);
CACHE_KEY.put(ACCESS_TOKEN, key + ACCESS_TOKEN + CP_COLON);
CACHE_KEY.put(REFRESH_TOKEN, key + REFRESH_TOKEN + CP_COLON);
CACHE_KEY.put(USER, key + USER + CP_COLON);
CACHE_KEY.put(MASK, key + MASK + CP_COLON);
}
/**
* 获取 AccessTokenKey
*
* @return key
*/
public static String getAccessTokenKey() {
return ACCESS_TOKEN_KEY;
}
/**
* 获取 AccessToken
*
* @param request HttpServletRequest
* @return AccessToken
*/
public static String getAccessToken(HttpServletRequest request) {
return HeaderUtils.getRequestParam(request, getAccessTokenKey());
}
/**
* 获取 Uid
*
* @param request HttpServletRequest
* @return Uid
*/
public static String getUid(HttpServletRequest request) {
return HeaderUtils.getRequestParam(request, BootCommonConstant.UID);
}
/**
* 创建 Token
*
* @param loginUser 登录用户信息
* @return Token 信息
*/
public static TokenDto createToken(LoginUserDto loginUser) {
Long userId = loginUser.getId();
remove(userId);
String accessToken = UuidUtils.get();
String refreshToken = UuidUtils.get();
Long accessTokenExpiryTime = CACHE_PARAM.expireTime();
Long refreshTokenExpiryTime = accessTokenExpiryTime + CACHE_PARAM.expireTime();
Long userExpiryTime = System.currentTimeMillis() + accessTokenExpiryTime * 1000;
RedisService redis = RedisUtils.get();
// 保存 accessToken信息
redis.set(getCacheKey(ACCESS_TOKEN, accessToken),
JSONObject.of("expiryTime", userExpiryTime, "loginUser", loginUser), refreshTokenExpiryTime);
// 保存 refreshToken信息
redis.set(getCacheKey(REFRESH_TOKEN, refreshToken), accessToken, refreshTokenExpiryTime);
// 保存用户 Token 信息
redis.set(getCacheKey(USER, userId),
JSONObject.of(ACCESS_TOKEN, accessToken, REFRESH_TOKEN, refreshToken), refreshTokenExpiryTime);
// 构建 Token 信息
TokenDto token = new TokenDto();
token.setAccessToken(accessToken);
token.setRefreshToken(refreshToken);
token.setExpiryTime(userExpiryTime);
return token;
}
/**
* 获取 LoginUser
*
* @return LoginUser
*/
public static LoginUserDto get() {
Map<String, Object> map = CommonHolder.get();
if (CollectionUtils.isEmpty(map)) {
throw new UnauthorizedError();
}
if (map.get(BootCommonConstant.AUTH) instanceof LoginUserDto loginUserDto) {
return loginUserDto;
}
if (map.get(BootCommonConstant.AUTHORIZATION) instanceof String accessToken) {
return get(accessToken);
}
throw new UnauthorizedError();
}
/**
* 获取 LoginUser
*
* @param id 用户 ID
* @return LoginUser
*/
public static LoginUserDto get(Long id) {
RedisService redis = RedisUtils.get();
JSONObject userCache = redis.get(getCacheKey(USER, id), JSONObject.class);
if (CollectionUtils.isEmpty(userCache)) {
return null;
}
String accessToken = userCache.getString(ACCESS_TOKEN);
return get(accessToken);
}
/**
* 从缓存获取 LoginUser
*
* @param accessToken AccessToken
* @return LoginUser
*/
public static LoginUserDto get(String accessToken) {
if (StringUtils.isBlank(accessToken)) {
return null;
}
return getFromCache(accessToken, true);
}
/**
* 移除缓存中登录用户信息
*
* @param idList 用户 ID 集合
*/
public static void remove(List<Long> idList) {
if (CollectionUtils.isEmpty(idList)) {
return;
}
for (Long id : idList) {
remove(id);
}
}
/**
* 移除缓存中登录用户信息
*
* @param id 用户 ID
*/
public static void remove(Long id) {
RedisService redis = RedisUtils.get();
JSONObject userCache = redis.get(getCacheKey(USER, id), JSONObject.class);
if (CollectionUtils.isEmpty(userCache)) {
return;
}
String accessToken = userCache.getString(ACCESS_TOKEN);
String refreshToken = userCache.getString(REFRESH_TOKEN);
redis.del(getCacheKey(ACCESS_TOKEN, accessToken));
redis.del(getCacheKey(REFRESH_TOKEN, refreshToken));
redis.del(getCacheKey(USER, id));
}
/**
* 刷新 Token
*
* @param refreshToken RefreshToken
* @return Token
*/
public static TokenDto refreshToken(String refreshToken) {
if (StringUtils.isBlank(refreshToken)) {
throw new BizError("refreshToken 不能为空");
}
RedisService redis = RedisUtils.get();
String accessToken = redis.get(getCacheKey(REFRESH_TOKEN, refreshToken), String.class);
if (StringUtils.isBlank(accessToken)) {
throw new BizError("token已过期,请重新登录");
}
LoginUserDto loginUser = getFromCache(accessToken, false);
if (loginUser == null) {
throw new BizError("token已过期,请重新登录");
}
return createToken(loginUser);
}
/**
* 获取是否忽略脱敏
*
* @return 是否忽略脱敏
*/
public static boolean isIgnoreMask() {
LoginUserDto loginUser = get();
if (Objects.isNull(loginUser)) {
throw new BizError("请先登录");
}
RedisService redis = RedisUtils.get();
Long time = redis.get(getCacheKey(MASK, loginUser.getId()), Long.class);
return CheckUtils.id(time);
}
/**
* 设置忽略脱敏
*/
public static void setIgnoreMask() {
LoginUserDto loginUser = get();
if (Objects.isNull(loginUser)) {
throw new BizError("请先登录");
}
RedisService redis = RedisUtils.get();
redis.set(getCacheKey(MASK, loginUser.getId()), Instant.now().toEpochMilli(), CACHE_PARAM.expireTime());
}
/**
* 移除忽略脱敏
*/
public static void removeIgnoreMask() {
LoginUserDto loginUser = get();
if (Objects.isNull(loginUser)) {
throw new BizError("请先登录");
}
RedisService redis = RedisUtils.get();
redis.del(getCacheKey(MASK, loginUser.getId()));
}
/**
* 从缓存获取 LoginUser
*
* @param accessToken AccessToken
* @param checkTime 是否检验有效期
* @return LoginUser
*/
private static LoginUserDto getFromCache(String accessToken, boolean checkTime) {
JSONObject data = RedisUtils.get().get(getCacheKey(ACCESS_TOKEN, accessToken), JSONObject.class);
if (CollectionUtils.isEmpty(data)) {
return null;
}
if (checkTime) {
Long expiryTime = data.getLong("expiryTime");
if (expiryTime < System.currentTimeMillis()) {
return null;
}
}
return JSON.to(LoginUserDto.class, data.getJSONObject("loginUser"));
}
/**
* 获取缓存 key
*
* @param keyType key 类型
* @param key Key
* @return 缓存 key
*/
private static String getCacheKey(String keyType, Object key) {
String keyPrefix = CACHE_KEY.get(keyType);
if (StringUtils.isBlank(keyPrefix)) {
throw new BizError("keyType 错误");
}
return keyPrefix + key;
}
}

View File

@@ -0,0 +1,125 @@
package xtools.app.sys.auth.utils;
import com.alibaba.fastjson2.JSON;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import xtools.app.common.cache.enums.AppCache;
import xtools.app.sys.auth.model.dto.InterfacePermDto;
import xtools.base.config.BaseParams;
import xtools.boot.cache.redis.base.RedisService;
import xtools.boot.cache.redis.utils.RedisUtils;
import xtools.core.CollectionUtils;
import xtools.core.StringUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* <p>Title : PremUtils</p>
* <p>Description : PremUtils</p>
* <p>DevelopTools : Idea_x64_v2026.1</p>
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
* <p>Company : org.xujun</p>
*
* @author : XuJun
* @version : 1.0.0
* @date : 2026/2/2 18:31
*/
public class PremUtils implements BaseParams {
/**
* 缓存参数
*/
private static final AppCache CACHE_PARAM = AppCache.AUTH_SYS_URI;
/**
* 接口权限类型映射
*/
private static final Map<String, String> PERM_TYPE_MAP;
// 初始化
static {
PERM_TYPE_MAP = new HashMap<>(CP_NUM7);
PERM_TYPE_MAP.put("1", "GET");
PERM_TYPE_MAP.put("2", "POST");
PERM_TYPE_MAP.put("3", "PUT");
PERM_TYPE_MAP.put("4", "DELETE");
PERM_TYPE_MAP.put("5", "PATCH");
PERM_TYPE_MAP.put("6", "HEAD");
PERM_TYPE_MAP.put("7", "OPTIONS");
}
/**
* 获取接口权限类型
*
* @param type 接口权限类型
* @return 接口权限类型
*/
public static String getPermType(String type) {
return PERM_TYPE_MAP.get(type);
}
/**
* 获取接口权限缓存 key
*
* @return 缓存 key
*/
public static String getCacheKey() {
return CACHE_PARAM.key();
}
/**
* 获取模块名称
*
* @param uri 请求 uri
* @return 模块名称
*/
public static String getModuleName(String uri) {
String[] split = uri.split(CP_SLASH);
int length = split.length;
if (length <= CP_NUM1) {
return CP_EMPTY;
} else if (length == CP_NUM2) {
return split[CP_NUM1];
} else {
return split[CP_NUM1] + CP_LINE + split[CP_NUM2];
}
}
/**
* 检查接口权限
*
* @param uri 请求 uri
* @param type 接口权限类型
* @param roleIds 角色 ID 集合
* @return 是否有权限
*/
public static boolean checkInterfacePerm(String uri, String type, List<Long> roleIds) {
String moduleName = getModuleName(uri);
if (StringUtils.isBlank(moduleName)) {
return false;
}
String cacheKey = moduleName + CP_COLON + type;
RedisService redis = RedisUtils.get();
List<?> list = redis.hashGet(getCacheKey(), cacheKey, List.class);
if (CollectionUtils.isEmpty(list)) {
return false;
}
PathMatcher pm = new AntPathMatcher();
for (Object obj : list) {
InterfacePermDto item = JSON.to(InterfacePermDto.class, obj);
String permUri = item.getUri();
if (!pm.match(permUri, uri)) {
continue;
}
List<Long> permRoleIds = item.getRoleIds();
if (CollectionUtils.isEmpty(permRoleIds)) {
return false;
}
return roleIds.stream().anyMatch(permRoleIds::contains);
}
return false;
}
}

View File

@@ -0,0 +1,36 @@
package xtools.app.sys.auth.whitelist;
import java.util.Set;
/**
* <p>Title : AuthWhitelist</p>
* <p>Description : AuthWhitelist</p>
* <p>DevelopTools : Idea_x64_v2026.1</p>
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
* <p>Company : org.xujun</p>
*
* @author : XuJun
* @version : 1.0.0
* @date : 2026/4/2 11:38
*/
public interface AuthWhitelist {
/**
* 添加权限白名单
*
* @return 权限白名单
*/
default Set<String> addAuth() {
return Set.of();
}
/**
* 添加登录白名单
*
* @return 登录白名单
*/
default Set<String> addLogin() {
return Set.of();
}
}