自学内容网 自学内容网

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

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

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

目录

权限判断注解

 AOP 实现

获取用户权限服务层

使用权限注解

解释

总结

优化


权限判断注解

PermissionCheck.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 实现

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 {


    @Autowired
    private 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 获取用户权限并集。
  • 检查用户是否具有所需权限,若不具有则抛出异常。

获取用户权限服务层

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 {


    @Autowired
    private UserRepository userRepository;


    @Autowired
    private RoleRepository roleRepository;


    @Autowired
    private 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 中,自动去重,得到权限并集。

使用权限注解

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 方法:

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 来增强安全性和用户信息的传递,提高系统的安全性和可扩展性。


原文地址:https://blog.csdn.net/a983677218/article/details/145175774

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!