Spring Security权限管理实现接口动态权限控制

以下是关于Spring Security权限管理实现接口动态权限控制的完整攻略:

1. 什么是接口动态权限控制

接口动态权限控制即根据用户的权限动态的对接口进行权限控制,这个过程可以分为两步:一是获取用户所拥有的权限,二是根据用户所拥有的权限动态的对接口进行控制。

2. Spring Security实现接口动态权限控制的步骤

以下是实现Spring Security接口动态权限控制的步骤:

2.1 配置SecurityConfig

在SecurityConfig中,我们可以通过配置一个Bean来获取指定用户的权限信息。

@Bean
public UserDetailsService userDetailsService() {
    return username -> {
        // 这里是获取指定用户的权限信息
        // 需要根据自己的业务逻辑来实现
    };
}

2.2 实现AccessDecisionManager接口

AccessDecisionManager是Spring Security中的权限决策器,它用于决策当前用户是否有访问该接口的权限。在AccessDecisionManager中,我们需要获取当前用户的权限列表,并将其与当前接口需要的权限列表进行比较,从而得出用户是否有访问该接口的权限。

@Component
public class CustomAccessDecisionManager implements AccessDecisionManager {

    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        List<String> userAuthorities = authentication.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.toList());
        List<String> requiredAuthorities = configAttributes.stream()
                .map(ConfigAttribute::getAttribute)
                .collect(Collectors.toList());
        // 如果用户拥有该接口所需要的所有权限,则允许访问。
        if (userAuthorities.containsAll(requiredAuthorities)) {
            return;
        }
        throw new AccessDeniedException("无权限访问");
    }

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}

2.3 配置SecurityMetadataSource

SecurityMetadataSource用于获取当前接口所需要的权限列表,在这里我们可以进行数据库或配置文件等方式的实现。

@Component
public class CustomSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    private final static Map<String, Collection<ConfigAttribute>> RESOURCE_ROLE_MAP = new ConcurrentHashMap<>();

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        FilterInvocation fi = (FilterInvocation) object;
        HttpServletRequest request = fi.getHttpRequest();
        String url = request.getRequestURI();
        // 获取当前接口所需要的权限列表
        Collection<ConfigAttribute> attributes = RESOURCE_ROLE_MAP.get(url);
        if (attributes == null || attributes.isEmpty()) {
            throw new AccessDeniedException("当前接口没有授权");
        }
        return attributes;
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

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

    /**
     * 动态添加权限,可以通过数据库获取
     * @param resourceRoleList
     */
    public static void setResourceRoleList(List<ResourceRoleDO> resourceRoleList) {
        resourceRoleList.forEach(resourceRoleDO -> {
            ConfigAttribute configAttribute = new SecurityConfig(resourceRoleDO.getRoleCode());
            if (RESOURCE_ROLE_MAP.containsKey(resourceRoleDO.getUrl())) {
                RESOURCE_ROLE_MAP.get(resourceRoleDO.getUrl()).add(configAttribute);
            } else {
                Set<ConfigAttribute> configAttributes = new HashSet<>();
                configAttributes.add(configAttribute);
                RESOURCE_ROLE_MAP.put(resourceRoleDO.getUrl(), configAttributes);
            }
        });
    }
}

2.4 配置FilterSecurityInterceptor

在FilterSecurityInterceptor中,我们需要设置AccessDecisionManager和SecurityMetadataSource。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomAccessDecisionManager customAccessDecisionManager;
    @Autowired
    private CustomSecurityMetadataSource customSecurityMetadataSource;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests()
                // 设置不需要验证的接口
                .antMatchers().permitAll()
                // 设置所有接口都需要鉴权
                .anyRequest().authenticated().and()
                // 添加动态权限控制拦截器
                .addFilterAfter(dynamicSecurityFilter(), FilterSecurityInterceptor.class);
    }

    @Bean
    public FilterInvocationSecurityMetadataSource customFilterInvocationSecurityMetadataSource() {
        return customSecurityMetadataSource;
    }

    @Bean
    public CustomAccessDecisionManager customAccessDecisionManager() {
        return customAccessDecisionManager;
    }

    /**
     * 配置动态权限控制拦截器
     * @return
     */
    public DynamicFilterInvocationSecurityMetadataSource dynamicFilterInvocationSecurityMetadataSource() {
        DynamicFilterInvocationSecurityMetadataSource dynamicFilterInvocationSecurityMetadataSource = new DynamicFilterInvocationSecurityMetadataSource();
        dynamicFilterInvocationSecurityMetadataSource.setSecurityMetadataSource(customSecurityMetadataSource);
        return dynamicFilterInvocationSecurityMetadataSource;
    }

    private FilterSecurityInterceptor dynamicSecurityFilter() {
        FilterSecurityInterceptor filterSecurityInterceptor = new FilterSecurityInterceptor();
        filterSecurityInterceptor.setSecurityMetadataSource(dynamicFilterInvocationSecurityMetadataSource());
        filterSecurityInterceptor.setAccessDecisionManager(customAccessDecisionManager());
        filterSecurityInterceptor.setObserveOncePerRequest(false);
        return filterSecurityInterceptor;
    }
}

以上就是Spring Security实现接口动态权限控制的完整攻略。

3. 示例说明

以下是两条示例说明:

3.1 动态添加权限

CustomSecurityMetadataSource.setResourceRoleList(resourceRoleList);

在这个方法中,我们通过查询数据库获取资源与角色的关系信息,并通过内存的方式动态的添加权限。

3.2 设置不需要验证的接口

在SecurityConfig中,我们可以通过设置不需要验证的接口,将这些接口开放出去,不需要进行权限控制。

http.csrf().disable().authorizeRequests()
    .antMatchers().permitAll()
    .anyRequest().authenticated().and()
    .addFilterAfter(dynamicSecurityFilter(), FilterSecurityInterceptor.class);

通过.antMatchers().permitAll()方法设置不需要验证的接口。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Security权限管理实现接口动态权限控制 - Python技术站

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

相关文章

  • Maven安装及MyEclipse中使用Maven

    下面是Maven安装及MyEclipse中使用Maven的完整攻略。 安装Maven 下载Maven 前往Maven官网下载最新的Maven版本,也可以通过镜像站点下载。 解压缩Maven 将下载的Maven压缩包解压到本地文件夹,例如解压到D盘根目录下的“apache-maven-3.8.3”。 配置环境变量 将Maven的bin目录添加到系统的PATH环…

    Java 2023年5月20日
    00
  • 将RestTemplate的编码格式改为UTF-8,防止乱码问题

    将 RestTemplate 的编码格式改为 UTF-8 可以通过以下步骤实现: 创建 UTF-8 格式的字符集 在 Java 中,可以通过 java.nio.charset.Charset 类来创建字符集。创建 UTF-8 格式的字符集可以使用以下代码: Charset utf8Charset = Charset.forName("UTF-8&q…

    Java 2023年5月20日
    00
  • 关于SpringBoot创建存储令牌的媒介类和过滤器的问题

    Spring Boot是一个流行的Java框架,可以用于快速开发Web应用程序。在Web应用程序中,通常需要使用token进行身份验证和授权,因此创建和存储令牌是非常重要的。本文将介绍如何使用Spring Boot创建媒介类和过滤器来存储和验证token并解决与存储令牌有关的问题。 创建TokenStorage媒介类 TokenStorage是一个媒介类,用…

    Java 2023年5月19日
    00
  • 详解Java如何优雅的使用策略模式

    详解Java如何优雅的使用策略模式 策略模式(Strategy Pattern)属于行为型设计模式,它定义了一系列算法,将每个算法封装起来,并使它们可以互换。策略模式让算法的变化独立于使用算法的客户端,客户端通过传递不同的策略对象来使用不同的算法。 在Java里,策略模式的实现有很多种方法,接下来将说明其中一种优雅的实现方式。 1. 定义接口和实现策略 首先…

    Java 2023年5月19日
    00
  • JAVA读取文件夹大小的几种方法实例

    下面是针对“JAVA读取文件夹大小的几种方法实例”的完整攻略。 一、问题概述 在开发Java应用程序中,我们难免会遇到计算文件夹大小的需求。那么,在Java中,我们有哪些方法来获取文件夹的大小呢?本文将为大家详细介绍Java中获取文件夹大小的几种方法。 二、方法一:使用File类 我们可以使用Java自带的File类获取文件夹的大小,具体步骤如下: 创建一个…

    Java 2023年5月20日
    00
  • Java基础之文件概述

    现在我来详细讲解一下Java基础之文件概述的完整攻略。 什么是文件? 首先,我们来了解一下什么是文件。文件是存储在计算机上的数据结构,可以是文本文件、图片文件、音频文件等等。在Java中,文件是由字节流或字符流读写的,这取决于文件的类型。 文件的基本操作 Java中常用的文件操作包括创建文件、读取文件、写入文件和删除文件。下面分别进行详细讲解。 创建文件 要…

    Java 2023年5月20日
    00
  • mybatisPlus自定义批量新增的实现代码

    下面我将详细讲解如何实现mybatisPlus自定义批量新增的实现代码,包括两条示例: 自定义批量新增实现代码 mybatisPlus并不支持批量新增操作,所以需要我们手动实现,下面是具体的代码实现: public interface CustomBatchInsertMapper<T> extends BaseMapper<T> {…

    Java 2023年5月20日
    00
  • Java简单实现调用命令行并获取执行结果示例

    首先我们需要了解Java如何调用命令行来执行外部的命令。在Java中,可以通过ProcessBuilder或Runtime.getRuntime().exec()两种方式实现。 使用ProcessBuilder调用命令行 ProcessBuilder是一个Java API,它提供了一个类来启动外部进程并与其进行交互。下面是一个简单的Java程序,它使用Pro…

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