Spring Security实现基于RBAC的权限表达式动态访问控制的操作方法

基于RBAC的权限表达式动态访问控制是Spring Security中常用的一种权限控制方式。以下是具体的实现方法:

1. 定义RBAC模型

可参考以下示例:

### 角色
1. 管理员
2. 普通用户

### 权限
1. 用户管理:创建、删除用户
2. 文章管理:查看、修改、删除所有文章;创建、修改、删除自己的文章

### 资源
- 用户: /user/**
- 文章: /article/**

2. 实现自定义AccessDecisionManager

继承于AbstractAccessDecisionManager并实现decide()方法。其中,自定义的AccessDecisionManager需要获取到当前用户的所有角色和请求所需要的权限,然后判断用户所拥有的角色中是否有权限,决定用户是否可以访问特定的请求。

方法参数说明:

  • authentication:当前登录用户的身份验证对象(即spring security的Authentication对象)
  • object:封装了请求信息(如请求URL),可以通过它来判断用户请求的资源
  • configAttributes:可以获取到访问某个资源所需要的角色

可参考以下示例:

@Component
public class CustomAccessDecisionManager extends AbstractAccessDecisionManager {

    private final UserService userService;

    public CustomAccessDecisionManager(UserService userService,
                                       List<AccessDecisionVoter<?>> decisionVoters) {
        super(decisionVoters);
        this.userService = userService;
    }

    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
            throws AccessDeniedException, InsufficientAuthenticationException {
        // 判断当前用户是否已登录
        if (authentication == null || !authentication.isAuthenticated()) {
            throw new AccessDeniedException("当前用户未登录");
        }

        // 获取当前用户所拥有的角色
        List<Role> userRoles = userService.getUserRoles(authentication.getName());
        if (userRoles == null || userRoles.isEmpty()) {
            throw new AccessDeniedException("当前用户未分配角色");
        }

        // 获取当前请求需要的角色
        Collection<String> requiredRoles = getRequiredRoles(configAttributes);
        if (requiredRoles == null || requiredRoles.isEmpty()) {
            throw new AccessDeniedException("当前请求未配置权限");
        }

        // 判断当前用户所拥有的角色和当前请求所需的角色是否匹配
        boolean isAuthorized = userRoles.stream()
                .map(Role::getRoleName)
                .anyMatch(requiredRoles::contains);
        if (!isAuthorized) {
            throw new AccessDeniedException("当前用户无权访问");
        }
    }

    private Collection<String> getRequiredRoles(Collection<ConfigAttribute> configAttributes) {
        if (configAttributes == null || configAttributes.isEmpty()) {
            return null;
        }
        return configAttributes.stream()
                .map(ConfigAttribute::getAttribute)
                .collect(Collectors.toList());
    }
}

3. 实现自定义Security MetadataSource

继承于FilterInvocationSecurityMetadataSource并实现getAttributes()supports()方法。其中,getAttributes()方法需要根据请求的URL返回该请求需要的角色,而supports()方法必须返回true。之后将该MetadataSource注入到Spring容器中。

可参考以下示例:

@Component
public class CustomInvocationSecurityMetadataSource extends AbstractSecurityInterceptor implements Filter {

    private final CustomAccessDecisionManager customAccessDecisionManager;

    public CustomInvocationSecurityMetadataSource(CustomAccessDecisionManager customAccessDecisionManager,
                                                   FilterInvocationSecurityMetadataSource metadataSource) {
        super();
        this.customAccessDecisionManager = customAccessDecisionManager;
        setAccessDecisionManager(customAccessDecisionManager);
        setSecurityMetadataSource(metadataSource);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        FilterInvocation filterInvocation = new FilterInvocation(request, response, chain);
        // 调用父类的beforeInvocation进行访问控制
        super.invoke(filterInvocation);
    }

    @Override
    public Class<?> getSecureObjectClass() {
        return FilterInvocation.class;
    }

    @Override
    public SecurityMetadataSource obtainSecurityMetadataSource() {
        return super.obtainSecurityMetadataSource();
    }

    @Override
    public void destroy() {}

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}

4. 配置Spring Security

对Spring Security进行自定义配置,将CustomAccessDecisionManager和CustomInvocationSecurityMetadataSource注册到Security配置中。

可参考以下示例:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final CustomAccessDecisionManager customAccessDecisionManager;
    private final FilterInvocationSecurityMetadataSource metadataSource;

    public SecurityConfig(CustomAccessDecisionManager customAccessDecisionManager,
                          FilterInvocationSecurityMetadataSource metadataSource) {
        this.customAccessDecisionManager = customAccessDecisionManager;
        this.metadataSource = metadataSource;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        /**
         * 为了演示方便,这里省略了其他配置
         */
        http.authorizeRequests()
            .anyRequest()
            .access("@customInvocationSecurityMetadataSource.decide(request,authentication)");
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        /**
         * 为了演示方便,这里省略了其他配置
         */
        auth.userDetailsService(userDetailsService());
    }

    @Bean
    public CustomAccessDecisionManager customAccessDecisionManager(UserService userService) {
        List<AccessDecisionVoter<?>> voters = Arrays.asList(
                new RoleVoter(),
                new AuthenticatedVoter(),
                new WebExpressionVoter()
        );
        return new CustomAccessDecisionManager(userService, voters);
    }

    @Bean
    public FilterInvocationSecurityMetadataSource customInvocationSecurityMetadataSource() throws Exception {
        UrlFilterInvocationSecurityMetadataSource metadataSource = new UrlFilterInvocationSecurityMetadataSource(
                securityInterceptor().getSecurityMetadataSource(), new PatternMatcher());
        // 用户 -> 角色 -> 权限
        metadataSource.addSecurityMapping(new SecurityMapping("/user/**", "ROLE_ADMIN"));
        metadataSource.addSecurityMapping(new SecurityMapping("/article/**", "ROLE_USER", "ROLE_ADMIN"));
        return metadataSource;
    }

    @Bean
    public CustomInvocationSecurityMetadataSource customInvocationSecurityMetadataSource(
            CustomAccessDecisionManager customAccessDecisionManager,
            FilterInvocationSecurityMetadataSource metadataSource
    ) {
        return new CustomInvocationSecurityMetadataSource(customAccessDecisionManager, metadataSource);
    }

    @Bean
    public SecurityInterceptor securityInterceptor() {
        return new SecurityInterceptor();
    }
}

示例说明

示例一:

当前用户为管理员,请求URL为/user/delete,则可以完成对当前用户的删除操作。若请求URL为/article/create则不能创建文章。

示例二:

当前用户为普通用户,请求URL为/user/create,则无法完成对其他用户创建的用户进行创建。但是可以通过请求URL/article/update来完成自己的文章修改。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Security实现基于RBAC的权限表达式动态访问控制的操作方法 - Python技术站

(0)
上一篇 2023年6月3日
下一篇 2023年6月3日

相关文章

  • 使用vscode搭建javaweb项目的详细步骤

    下面是使用VSCode搭建JavaWeb项目的详细步骤。 步骤一:安装必要的插件 在VsCode的扩展中心搜索Java Extension Pack并安装。它包含了多个必要的插件,如 Java Language Support、Debugger for Java 等。 步骤二:创建Maven项目 安装Maven。安装完成后在命令行中输入 mvn -versi…

    Java 2023年5月26日
    00
  • Springboot单体架构http请求转换https请求来支持微信小程序调用接口

    让我们来详细讲解“Springboot单体架构http请求转换https请求来支持微信小程序调用接口”的攻略。 背景介绍 微信小程序在与后端交互时,要求所有的接口都必须使用HTTPS协议,而SpringBoot单体架构默认是使用HTTP协议的。所以,我们需要将HTTP请求转换为HTTPS请求,来支持微信小程序调用接口。 实现过程 以下是实现过程的详细步骤: …

    Java 2023年5月23日
    00
  • Oracle JDBC连接BUG解决方案

    下面是详细的“Oracle JDBC连接BUG解决方案”的攻略。 问题描述 使用Java程序连接Oracle数据库时,经常会遇到连接时出现“ORA-12519, TNS:no appropriate service handler found”的错误提示,造成无法连接数据库的情况。这个问题一般出现在高并发的情况下。 原因分析 这个问题的产生是由于Oracle…

    Java 2023年5月23日
    00
  • ajax的json传值方式在jsp页面中的应用

    下面我将为你详细讲解“ajax的json传值方式在jsp页面中的应用”的攻略。 1. AJAX简介 AJAX(Asynchronous JavaScript and XML)即异步JavaScript和XML,是指通过JavaScript、XMLHttpRequest对象和DOM实现局部更新页面的技术。AJAX技术使得页面在不刷新的情况下,能够向服务器发起异…

    Java 2023年5月20日
    00
  • JAVA对称加密算法PBE定义与用法实例分析

    JAVA对称加密算法PBE定义与用法实例分析 简介 PBE(Password Based Encryption)是基于密码的加密算法,在数据加密中使用口令替代了传统的密钥,是一种轻量级加密算法。PBE算法不需要证书链和公钥证书等机构,实现简单便捷,容易实施。PBE算法又称为基于口令加密。 PBE算法加密实现步骤 1.搜集用户输入 从用户输入中获取需要加密的数…

    Java 2023年5月19日
    00
  • Java中的SecurityException是什么?

    Java中的SecurityException是一种运行时异常,表示安全限制被违反。当Java应用程序试图执行需要更高级别权限才能执行的操作时,就会抛出SecurityException异常。例如,如果Java应用程序运行在沙箱中,将尝试访问本地文件系统或网络时,就会抛出SecurityException异常。 通常情况下,SecurityException…

    Java 2023年4月27日
    00
  • java实现简易扑克牌游戏

    Java实现简易扑克牌游戏攻略 简述本游戏 本游戏为一款基于Java的简易扑克牌游戏,玩家可以通过交互式的界面进行牌局游戏。游戏规则沿用经典扑克牌规则,有四个花色(黑桃、红桃、梅花、方块),每个花色下面有十三张牌(A、2、3、4、5、6、7、8、9、10、J、Q、K),共五十二张牌。 游戏实现逻辑 创建一个52张牌的扑克牌集合,包含所有牌的花色和点数; 打乱…

    Java 2023年5月19日
    00
  • Spring mvc实现Restful返回json格式数据实例详解

    下面是关于“Spring MVC实现Restful返回JSON格式数据实例详解”的完整攻略,包含两个示例说明。 Spring MVC实现Restful返回JSON格式数据 在本文中,我们将介绍如何使用Spring MVC实现Restful返回JSON格式数据。 步骤1:添加依赖 首先,我们需要在pom.xml中添加Spring MVC和Jackson的依赖。…

    Java 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部