Spring Boot中使用AOP实现权限管理

devtools/2025/1/18 2:57:23/

       权限管理的实现方法有很多种,也有很多集成不错的框架。现在用AOP和自定义注解实现一个简单易理解的权限管理~

       默认已经有做好了RBAC(role  based  access  control),基于角色的访问控制。就是数据库中已经有了用户表,角色表,权限表,用户角色表,角色权限表。我们判断权限是取一个用户所有角色拥有权限的并集。

目录

权限判断注解

 AOP 实现

获取用户权限服务层

使用权限注解

解释

总结

优化


权限判断注解

PermissionCheck.java

java">import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PermissionCheck {String value();
}

 AOP 实现

java">import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;@Aspect
@Component
public class PermissionAspect {@Autowiredprivate PermissionService permissionService;@Pointcut("execution(* *(..)) && @annotation(PermissionCheck)")public void permissionCheckPointcut() {}@Before("permissionCheckPointcut()")public void checkPermission() throws Throwable {MethodSignature signature = (MethodSignature) ProxyMethodInvocation.currentInvocation().getMethod().getSignature();Method method = signature.getMethod();PermissionCheck permissionCheck = method.getAnnotation(PermissionCheck.class);String requiredPermission = permissionCheck.value();String username = getUsernameFromRequest();Set<String> userPermissions = permissionService.getUserPermissions(username);if (!userPermissions.contains(requiredPermission)) {throw new RuntimeException("没有权限");}}private String getUsernameFromRequest() {// 从请求中获取用户名,例如从 token 或 session 中获取return "username";}
}

解释:

  • @Pointcut("execution(* *(..)) && @annotation(PermissionCheck)"):定义切点为带有 PermissionCheck 注解的所有方法。
  • @Before("permissionCheckPointcut()"):在这些方法执行前执行 checkPermission 方法。
  • MethodSignature signature = (MethodSignature) ProxyMethodInvocation.currentInvocation().getMethod().getSignature();:获取方法签名。
  • Method method = signature.getMethod();:获取被调用的方法。
  • PermissionCheck permissionCheck = method.getAnnotation(PermissionCheck.class);:获取方法上的 PermissionCheck 注解。
  • String requiredPermission = permissionCheck.value();:获取注解中的权限信息。
  • Set<String> userPermissions = permissionService.getUserPermissions(username);:调用 PermissionService 获取用户权限并集。
  • 检查用户是否具有所需权限,若不具有则抛出异常。

获取用户权限服务层

java">import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashSet;
import java.util.List;
import java.util.Set;@Service
public class PermissionService {@Autowiredprivate UserRepository userRepository;@Autowiredprivate RoleRepository roleRepository;@Autowiredprivate PermissionRepository permissionRepository;public Set<String> getUserPermissions(String username) {User user = userRepository.findByUsername(username);List<Role> roles = roleRepository.findByUserId(user.getId());Set<String> permissions = new HashSet<>();for (Role role : roles) {List<Permission> rolePermissions = permissionRepository.findByRoleId(role.getId());for (Permission permission : rolePermissions) {permissions.add(permission.getName());}}return permissions;}
}

解释:

  • getUserPermissions 方法:
    • 根据用户名查找用户。
    • 通过用户查找其所有角色。
    • 遍历角色,找到每个角色对应的权限列表。
    • 将权限存储在 HashSet 中,自动去重,得到权限并集。

使用权限注解

java">import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/api")
public class SampleController {@GetMapping("/createUser")@PermissionCheck("user::add")public String createUser() {// 执行创建用户的逻辑return "用户创建成功";}@GetMapping("/editUser")@PermissionCheck("user::edit")public String editUser() {// 执行编辑用户的逻辑return "用户编辑成功";}
}

解释

1. PermissionService

  • 使用 HashSet 存储用户权限,自动去重,确保权限列表中的元素唯一性。
  • 遍历用户的所有角色,将每个角色的权限添加到 HashSet 中,实现权限并集的计算。

2. PermissionAspect

  • 从方法注解中获取所需的权限信息。
  • 通过 PermissionService 获取用户权限并集。
  • 检查用户是否具有所需权限,若不具有则抛出异常。

总结

  • 服务层

    • PermissionService 负责根据用户查找其所有角色的权限,并将这些权限存储在 HashSet 中,实现权限并集的计算。
  • AOP 切面

    • 使用 PermissionAspect 在方法执行前检查用户是否具有所需权限。
  • 自定义注解

    • PermissionCheck 注解用于标记需要权限检查的方法,并传递权限信息。

优化

       在实际应用中,还可以进一步优化,例如使用缓存来提高权限查询的性能,避免频繁的数据库查询,以及使用更安全的认证和授权机制,如 JWT 等。

以下是使用 JWT 提取用户名的示例,用于 getUsernameFromRequest 方法:

java">import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;private String getUsernameFromRequest() {String token = getTokenFromRequest();Claims claims = Jwts.parser().setSigningKey("your_secret_key").parseClaimsJws(token).getBody();return claims.getSubject();
}private String getTokenFromRequest() {// 从请求头中获取 JWT 令牌HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();String bearerToken = request.getHeader("Authorization");if (bearerToken.startsWith("Bearer ")) {return bearerToken.substring(7);}return null;
}

解释:

  • getUsernameFromRequest 方法:
    • 从请求中获取 JWT 令牌。
    • 解析 JWT 令牌获取 claims
    • 从 claims 中获取用户名(通常存储在 subject 字段)。

       这样可以根据用户的多个角色进行权限并集的计算和检查,同时使用 JWT 来增强安全性和用户信息的传递,提高系统的安全性和可扩展性。


http://www.ppmy.cn/devtools/151443.html

相关文章

MiniCPM-o 2.6:开源大型语言模型在多模态任务上超越GPT-4o和Claude 3.5

MiniCPM-o 2.6是一款开源的大型语言模型&#xff08;LLM&#xff09;&#xff0c;其在多模态任务上的表现令人瞩目&#xff0c;成功超越了GPT-4o和Claude 3.5等业界知名模型。以下是对MiniCPM-o 2.6的详细介绍&#xff1a; 一、卓越的多模态能力 MiniCPM-o 2.6采用了先进的端…

ElasticSearch的劈山斧-自定义评分

ElasticSearch自定义评分 一、适用的场景 1.基本介绍 ES的使用中&#xff0c;ES会对我们匹配文档进行相关度评分。但对于一些定制化的场景&#xff0c;默认评分规则满足不了我们的要求。这些定制化场景&#xff0c;ES也是推出了自定义评分方式来进行支持。可以使用ES提供的一…

Go语言之路————条件控制:if、for、switch

Go语言之路————if、for、switch 前言ifforswitchgoto和label 前言 我是一名多年Java开发人员&#xff0c;因为工作需要现在要学习go语言&#xff0c;Go语言之路是一个系列&#xff0c;记录着我从0开始接触Go&#xff0c;到后面能正常完成工作上的业务开发的过程&#xff0…

大模型——RAG

什么是RAG RAG&#xff08;Retrieval Augmented Generation,检索增强生成&#xff09;&#xff0c;LLM在回答问题或生成文本时&#xff0c;先会从大量文档中检索出相关的信息&#xff0c;然后基于这些信息生成回答或文本&#xff0c;从而提高预测质量。 R:检索器模块 在RAG中…

云手机技术怎么实现的?

前言 随着亚矩阵云手机在跨境电商、海外社媒矩阵搭建、出海运营、海外广告投放、国内新媒体矩阵运营、品牌应用矩阵运营等领域内的普及和使用&#xff0c;云手机的理念已经被越来越多人所接受和认同。今天我们就一起来浅析一下&#xff0c;到底云手机的技术是怎么实现的&#…

windows安装docker

安装 首先确保windows启用Hyper-V&#xff0c;子linux系统和虚拟机平台&#xff0c;且cpu开启虚拟化 重启等待应用生效 安装doxker desktop 下载链接 打开cmd&#xff0c;输入docker version查看安装情况 在服务类型查看docker服务是否启动&#xff0c;不是进入服务修改为自…

LDN的蓝牙双模键盘帮助文档

文档索引 已支持的PCB列表(仅列出少部分)&#xff1a;键盘特性硬件软件键盘以及驱动蓝牙模式USB模式 驱动功能介绍主界面键盘列表页面键盘配置&#xff08;使用双模键盘的请务必细看本说明&#xff09;功能层配置(改键)触发层配置(改FN键等触发功能)功能选择&#xff08;重要&a…

MyBatis——XML映射文件

在MyBatis中&#xff0c;既可以通过注解的方式配置SQL语句&#xff0c;也可以通过XML映射文件的方式配置SQL语句。对于简单的SQL语句建议直接通过注解的方式配置SQL语句&#xff1a; Delete("delete from user where id#{id}") Integer deleteById(Integer id);但是…