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日

相关文章

  • 浅析Java的Spring框架中IOC容器容器的应用

    浅析Java的Spring框架中IOC容器容器的应用 什么是IOC容器 IoC(Inversion of Control),即控制反转,是一种设计思想,一种面向对象编程中的思想,其主要的思想是将原本需要自己创建对象的控制权交给Spring容器,由容器来统一管理和创建对象。IoC容器是Spring框架的核心,它管理着应用程序中的所有对象。 IoC容器的应用 I…

    Java 2023年5月19日
    00
  • Spring请求参数校验功能实例演示

    我来为您讲解“Spring请求参数校验功能实例演示”的完整攻略,首先我们需要了解以下几点: Spring请求参数校验依赖于Hibernate Validator(JSR 380)。 在Controller层使用@Valid注解对参数进行校验。 在参数对象中使用Hibernate Validator的注解对属性进行校验。 接下来我们将透过两个示例来进行具体演示…

    Java 2023年5月20日
    00
  • 详解Spring Security怎么从数据库加载我们的用户

    下面是详解Spring Security怎么从数据库加载我们的用户的完整攻略。 准备工作 首先,我们需要在项目中引入Spring Security和Spring JDBC的依赖。具体可以在maven中添加如下依赖: <dependency> <groupId>org.springframework.security</group…

    Java 2023年5月20日
    00
  • 详解spring-boot集成elasticsearch及其简单应用

    详解spring-boot集成elasticsearch及其简单应用 在使用spring-boot构建web应用时,我们经常需要一种快速高效的搜索方案来提升用户体验。Elasticsearch是目前比较受欢迎的搜索引擎之一,它具有强大的查询引擎、分布式性能和数据分析能力。本文将详解如何在spring-boot中使用Elasticsearch,并展示一个简单的…

    Java 2023年5月20日
    00
  • java jackson 将对象转json时,忽略子对象的某个属性操作

    要忽略 Jackson 序列化对象中子对象的某个属性,可以使用 Jackson 的注解 @JsonIgnore 或 @JsonIgnoreProperties。下面是详细攻略: 1. @JsonIgnoreProperties @JsonIgnoreProperties 注解可以添加到需要进行序列化和反序列化的类上,以忽略某些属性。比如说有一个 User 类…

    Java 2023年5月20日
    00
  • Java国际化简介_动力节点Java学院整理

    Java国际化简介 什么是Java国际化 Java国际化是指Java应用程序能够适应多种本地化语言和文化习惯的能力。对于包含不同语言或文化背景的用户,Java应用程序可以根据用户的语言环境改变显示的文本和消息。 Java国际化主要涉及以下三个方面: 文本显示问题。不同的语言使用不同的字符编码,如中文是utf-8,英文是ISO-8859-1。当不同语言的用户使…

    Java 2023年5月20日
    00
  • Spring MVC学习教程之视图深入解析

    “Spring MVC学习教程之视图深入解析”是一篇关于 Spring MVC 视图的深度解析的文章,主要介绍了 Spring MVC 中视图的相关知识。下文将详细讲解该文章的完整攻略。 一、文章概述 文章分为四个部分,分别是 “前言”、“视图简介”、“视图技术解析” 和 “总结”。下文将对各个部分进行详细解释。 1. 前言 文章从 Spring MVC 的…

    Java 2023年6月15日
    00
  • SpringSceurity实现短信验证码功能的示例代码

    下面我将详细讲解如何使用Spring Security实现短信验证码功能。这里假设你已经有了一个基于Spring Security的Web应用程序,现在要添加短信验证码功能。 准备工作 在开始实现之前需要进行一些准备工作: 1.添加Spring Security支持短信验证码功能的依赖; 在pom.xml中添加以下依赖: <dependency>…

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