添加权限校验

This commit is contained in:
luke 2025-06-09 19:33:04 +08:00
parent 7886ec3267
commit c491ab9cc2
2 changed files with 103 additions and 4 deletions

20
config/mysql/dml.txt Normal file
View File

@ -0,0 +1,20 @@
INSERT INTO role (role_code, role_name) VALUES ('ADMIN', '管理员');
INSERT INTO role (role_code, role_name) VALUES ('USER', '普通用户');
INSERT INTO role (role_code, role_name) VALUES ('GUEST', '访客');
-- 管理员全部可看
INSERT INTO role_file_rule (role_id, file_pattern, remark) VALUES
(1, '/', '管理员可访问所有文件');
-- 普通用户可访问自己目录和公共目录
INSERT INTO role_file_rule (role_id, file_pattern, remark) VALUES
(2, '/public/${username}-', '用户可访问以用户名开头的文件');
INSERT INTO role_file_rule (role_id, file_pattern, remark) VALUES
(2, '/public/2025年', '用户可访问公共文件');
-- 访客只能访问公共目录
INSERT INTO role_file_rule (role_id, file_pattern, remark) VALUES
(3, '/public/2025年', '访客可访问公共文件');
---- 为用户赋予权限 ----
INSERT INTO user_role (user_id, role_id) values ('1', '1');
INSERT INTO user_role (user_id, role_id) values ('2', '2');

View File

@ -1,14 +1,20 @@
package com.knowledge.base.infrastructure.north.controller; package com.knowledge.base.infrastructure.north.controller;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.knowledge.base.application.service.UserAppService; import com.knowledge.base.application.service.UserAppService;
import com.knowledge.base.infrastructure.config.ConstantConfig; import com.knowledge.base.infrastructure.config.ConstantConfig;
import com.knowledge.base.infrastructure.north.dto.role.RoleFileRuleDTO;
import com.knowledge.base.infrastructure.north.dto.role.UserRoleDTO; import com.knowledge.base.infrastructure.north.dto.role.UserRoleDTO;
import com.knowledge.base.infrastructure.north.dto.user.UserDTO; import com.knowledge.base.infrastructure.north.dto.user.UserDTO;
import com.knowledge.base.infrastructure.north.dto.user.UserTokenDTO; import com.knowledge.base.infrastructure.north.dto.user.UserTokenDTO;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@ -18,20 +24,93 @@ import java.util.Optional;
@RequiredArgsConstructor @RequiredArgsConstructor
public class UserQueryController { public class UserQueryController {
private static final Logger LOGGER = LoggerFactory.getLogger(UserQueryController.class);
private final UserAppService userAppService; private final UserAppService userAppService;
@GetMapping("/check") @GetMapping("/check")
public ResponseEntity<?> check( public ResponseEntity<?> check(
@CookieValue(value = ConstantConfig.COOKIE_KEY, required = false) String cookieToken, @CookieValue(value = ConstantConfig.COOKIE_KEY, required = false) String cookieToken,
@RequestHeader(value = "Authorization", required = false) String headerToken @RequestHeader(value = "Authorization", required = false) String headerToken,
HttpServletRequest request
) { ) {
String token = headerToken != null ? headerToken : cookieToken; String token = headerToken != null ? headerToken : cookieToken;
if (userAppService.isValidToken(token)) { String requestUri = request.getRequestURI();
return ResponseEntity.ok(Map.of("code", 0, "msg", "校验成功"));
} LOGGER.info("[权限校验] token={}, uri={}", token, requestUri);
if (token == null || token.isBlank()) {
LOGGER.warn("[权限校验] 未提供token拒绝访问");
return ResponseEntity.status(401).body(Map.of("code", 401, "msg", "未授权")); return ResponseEntity.status(401).body(Map.of("code", 401, "msg", "未授权"));
} }
Optional<UserTokenDTO> userTokenOpt = userAppService.findToken(token);
if (userTokenOpt.isEmpty()) {
LOGGER.warn("[权限校验] token无效: {}", token);
return ResponseEntity.status(401).body(Map.of("code", 401, "msg", "无效token"));
}
Long userId = userTokenOpt.get().getUserId();
LOGGER.info("[权限校验] 解析到userId={}", userId);
// 查询用户角色
List<UserRoleDTO> userRoles = userAppService.listUserRoles(userId);
if (userRoles == null || userRoles.isEmpty()) {
LOGGER.warn("[权限校验] 用户[{}]未分配任何角色", userId);
return ResponseEntity.status(403).body(Map.of("code", 403, "msg", "无角色权限"));
}
List<Long> roleIds = Lists.newArrayList();
for (UserRoleDTO userRole : userRoles) {
roleIds.add(userRole.getRoleId());
}
LOGGER.info("[权限校验] 用户[{}]拥有角色: {}", userId, roleIds);
// 合并所有角色的规则
List<RoleFileRuleDTO> allRules = Lists.newArrayList();
for (Long roleId : roleIds) {
List<RoleFileRuleDTO> rules = userAppService.listRoleFileRules(roleId);
LOGGER.info("[权限校验] 角色[{}]规则数={}", roleId, rules != null ? rules.size() : 0);
if (rules != null) allRules.addAll(rules);
}
Optional<UserDTO> userDTO = userAppService.findById(userId);
String userName = userDTO.isPresent() ? userDTO.get().getUsername() : StrUtil.EMPTY;
boolean hasPermission = false;
for (RoleFileRuleDTO rule : allRules) {
String pattern = rule.getFilePattern();
if (pattern == null) continue;
// 动态替换占位符
if (pattern.contains("${username}") && userName != null) {
pattern = pattern.replace("${username}", userName);
}
// 管理员全访问pattern为/ pattern为.* 都放行
if ("/".equals(pattern) || ".*".equals(pattern)) {
LOGGER.info("[权限校验] 用户[{}]的角色规则[{}]允许全路径访问: {}", userId, pattern, requestUri);
hasPermission = true;
break;
}
// 先前缀匹配再正则匹配
if (requestUri.startsWith(pattern) || requestUri.matches(pattern)) {
LOGGER.info("[权限校验] 用户[{}]的角色规则[{}]允许访问: {}", userId, pattern, requestUri);
hasPermission = true;
break;
}
}
if (hasPermission) {
LOGGER.info("[权限校验] 访问通过: userId={}, uri={}", userId, requestUri);
return ResponseEntity.ok(Map.of("code", 0, "msg", "权限校验通过"));
} else {
LOGGER.warn("[权限校验] 拒绝访问: userId={}, uri={}, 无匹配规则", userId, requestUri);
return ResponseEntity.status(403).body(Map.of("code", 403, "msg", "无访问权限"));
}
}
@GetMapping("/username") @GetMapping("/username")
public ResponseEntity<?> getUsernameByToken( public ResponseEntity<?> getUsernameByToken(
@CookieValue(value = ConstantConfig.COOKIE_KEY, required = false) String cookieToken, @CookieValue(value = ConstantConfig.COOKIE_KEY, required = false) String cookieToken,