From c491ab9cc21aff1dff95949e8ab87488acbf3650 Mon Sep 17 00:00:00 2001 From: luke Date: Mon, 9 Jun 2025 19:33:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9D=83=E9=99=90=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/mysql/dml.txt | 20 +++++ .../north/controller/UserQueryController.java | 87 ++++++++++++++++++- 2 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 config/mysql/dml.txt diff --git a/config/mysql/dml.txt b/config/mysql/dml.txt new file mode 100644 index 0000000..9800c2f --- /dev/null +++ b/config/mysql/dml.txt @@ -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'); diff --git a/src/main/java/com/knowledge/base/infrastructure/north/controller/UserQueryController.java b/src/main/java/com/knowledge/base/infrastructure/north/controller/UserQueryController.java index 7eaf951..20a5687 100644 --- a/src/main/java/com/knowledge/base/infrastructure/north/controller/UserQueryController.java +++ b/src/main/java/com/knowledge/base/infrastructure/north/controller/UserQueryController.java @@ -1,14 +1,20 @@ 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.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.user.UserDTO; import com.knowledge.base.infrastructure.north.dto.user.UserTokenDTO; import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletRequest; import java.util.List; import java.util.Map; import java.util.Optional; @@ -18,18 +24,91 @@ import java.util.Optional; @RequiredArgsConstructor public class UserQueryController { + private static final Logger LOGGER = LoggerFactory.getLogger(UserQueryController.class); + private final UserAppService userAppService; @GetMapping("/check") public ResponseEntity check( @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; - if (userAppService.isValidToken(token)) { - return ResponseEntity.ok(Map.of("code", 0, "msg", "校验成功")); + String requestUri = request.getRequestURI(); + + LOGGER.info("[权限校验] token={}, uri={}", token, requestUri); + + if (token == null || token.isBlank()) { + LOGGER.warn("[权限校验] 未提供token,拒绝访问"); + return ResponseEntity.status(401).body(Map.of("code", 401, "msg", "未授权")); + } + + Optional 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 userRoles = userAppService.listUserRoles(userId); + if (userRoles == null || userRoles.isEmpty()) { + LOGGER.warn("[权限校验] 用户[{}]未分配任何角色", userId); + return ResponseEntity.status(403).body(Map.of("code", 403, "msg", "无角色权限")); + } + + List roleIds = Lists.newArrayList(); + for (UserRoleDTO userRole : userRoles) { + roleIds.add(userRole.getRoleId()); + } + LOGGER.info("[权限校验] 用户[{}]拥有角色: {}", userId, roleIds); + + // 合并所有角色的规则 + List allRules = Lists.newArrayList(); + for (Long roleId : roleIds) { + List rules = userAppService.listRoleFileRules(roleId); + LOGGER.info("[权限校验] 角色[{}]规则数={}", roleId, rules != null ? rules.size() : 0); + if (rules != null) allRules.addAll(rules); + } + + Optional 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", "无访问权限")); } - return ResponseEntity.status(401).body(Map.of("code", 401, "msg", "未授权")); } @GetMapping("/username")