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来完成自己的文章修改。

阅读剩余 78%

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

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

相关文章

  • Java的Struts框架中的主题模板和国际化设置

    Java的Struts框架中的主题模板和国际化设置提供了一套全局约束的方式来统一管理Web应用的界面样式和用户语言环境,本文将为您提供完整的攻略,包括如何设置和使用主题模板和国际化设置。 设置主题模板 在Struts框架中,使用主题模板可以方便地统一管理Web应用的界面样式,通过以下步骤可以设置主题模板: 1. 在struts.xml中进行配置 在strut…

    Java 2023年5月20日
    00
  • Maven构建生命周期详细介绍

    介绍Maven构建生命周期之前,首先需要了解一下Maven中的概念: POM(Parent Object Model): Maven项目的核心文件,包含了项目的基本信息和配置信息。 Artifact(构件):是一个独立的、可重用的软件组件,包括代码和其所依赖的库、配置文件等。 Dependency(依赖):描述当前项目所依赖的其他构件,用于下载构件到本地仓库…

    Java 2023年5月20日
    00
  • JavaWeb文件上传与下载功能解析

    JavaWeb文件上传与下载功能解析 文件上传功能 在JavaWeb中,文件上传主要包括三个部分:前端页面、后端处理、文件保存。 前端页面 文件上传的前端页面需要使用form表单,同时表单属性需要设置为enctype=”multipart/form-data”,以支持文件上传。例如: <form action="upload" me…

    Java 2023年5月19日
    00
  • Java实现员工管理系统

    Java实现员工管理系统攻略 实现员工管理系统的步骤如下: 第一步:确定需求 在开发一款软件之前,我们需要明确该软件需要满足哪些需求。对于员工管理系统,我们至少需要以下几个功能: 添加员工信息; 删除员工信息; 修改员工信息; 查询员工信息。 如果需要更多的功能,可以在需求分析阶段确定。 第二步:搭建开发环境 在确定了需求之后,我们需要搭建 Java 开发环…

    Java 2023年5月30日
    00
  • Java JDK1.7对字符串的BASE64编码解码方法

    Java JDK 1.7版本提供了对字符串进行 BASE64 编码和解码的方法,它们是 java.util.Base64 和 javax.xml.bind.DatatypeConverter。 使用java.util.Base64类进行BASE64编码和解码 java.util.Base64 是 JDK 1.8 新增的类,它提供了两个静态方法 getEnco…

    Java 2023年5月20日
    00
  • SpringMVC和Ajax的交互详解(手工处理)

    SpringMVC和Ajax的交互详解(手工处理) 在Web开发中,SpringMVC和Ajax的结合使用非常常见。本文将介绍如何使用SpringMVC和Ajax进行交互,并手工处理Ajax请求和响应。 步骤一:创建SpringMVC项目 我们可以使用Maven来创建一个新的SpringMVC项目。在创建项目时,我们需要选择“webapp”类型的项目,并添加…

    Java 2023年5月17日
    00
  • 详解Java枚举类在生产环境中的使用方式

    让我来详细讲解一下Java枚举类在生产环境中的使用方式。 1. 什么是枚举类? 枚举类在Java中是一种特殊的类,它定义了一组常量,这些常量在枚举类型中只有一个实例,并且可以在代码中以常量的形式引用。 在Java中,我们可以通过定义枚举类来限制变量的值。枚举类型常常用来代替一些特定的常量,比如性别(男、女)、星期(周一到周日)等。 下面是一个简单的枚举类示例…

    Java 2023年5月23日
    00
  • WebSocket整合SSM(Spring,Struts2,Maven)的实现示例

    下面我将为你详细讲解“WebSocket整合SSM的实现示例”攻略。 一、实现方案 我们的实现方案是使用Spring+Struts2+MyBatis构建一个SSM项目并整合WebSocket。 1.1 准备工作 首先需要准备以下开发环境 JDK 1.8 Eclipse Tomcat 8.0及以上版本 Maven 1.2 导入项目 使用Maven创建一个Web…

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