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

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

1. 简介

在Spring Security中,我们可以使用基于注解的安全性,以控制方法响应、请求类型等。但是,如果我们需要跟具体的业务数据绑定的话,我们就需要根据规则来控制具体的访问权限。

在这种情况下,就需要使用Spring Security提供的“动态授权”功能了。本文将介绍如何使用动态授权功能来精细管理用户权限。

2. 动态授权原理

Spring Security中的动态授权,是通过实现权限控制的接口来达到的。主要通过实现AccessDecisionManager接口和AccessDecisionVoter接口来实现。

AccessDecisionManager接口提供了访问决策,它用于限定某个Subject允许访问哪种资源。

AccessDecisionVoter接口是AccessDecisionManager的一个具体实现。它可以进行“投票”,来判断是否允许访问某个资源。

3. 实现动态授权

下面是具体的实现步骤:

3.1. 定义自定义权限管理器

首先,在项目中定义一个自定义的权限管理器,在这里我们继承了AccessDecisionManager接口。

定义完成后,重写父接口中的方法decide()decide()方法会对用户的拥有角色和尝试访问资源进行比较,如果判断用户拥有该资源访问权限则返回,否则就抛出InvalidAuthorityException异常。

@Service
public class CustomAccessDecisionManager implements AccessDecisionManager {

    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        if(configAttributes == null) {
            return;
        }
        Iterator<ConfigAttribute> iterator = configAttributes.iterator();
        while(iterator.hasNext()) {
            ConfigAttribute configAttribute = iterator.next();
            String needRole = configAttribute.getAttribute();
            for(GrantedAuthority grantedAuthority : authentication.getAuthorities()) {
                if(grantedAuthority.getAuthority().equals(needRole)) {
                    return;
                }
            }
        }
        throw new AccessDeniedException("您没有访问该资源的权限");
    }

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

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

3.2. 定义自定义投票器

定义完权限管理器后,我们就要定义自定义的投票器了,继承AccessDecisionVoter接口,这个类主要负责解析用户请求中的资源路径、资源类型和权限集合,进行投票决策。

和之前一样,我们要实现该接口中重写的方法vote()。根据用户的访问路径和权限,它会“投票”给权限管理器,最终决定用户是否有权访问。

在这里,我们实现了两个投票器来进行权限控制。其中,一些接口需要admin角色才能访问,而其他接口不需要。

示例代码:

@Component
public class UrlAccessDecisionVoter implements AccessDecisionVoter<Object>{
    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

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

    @Override
    public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
        int result = AccessDecisionVoter.ACCESS_ABSTAIN;
        Object principal = authentication.getPrincipal();
        if (!(principal instanceof UserDetails)) {
            return result;
        }
        UserDetails user = (UserDetails) principal;

        for (ConfigAttribute attribute : attributes) {
            if ("ROLE_ADMIN".equals(attribute.getAttribute())) {
                result = AccessDecisionVoter.ACCESS_DENIED;
                for (GrantedAuthority authority : user.getAuthorities()) {
                    if ("ROLE_ADMIN".equals(authority.getAuthority())) {
                        return AccessDecisionVoter.ACCESS_GRANTED;
                    }
                }
            } else {
                result = AccessDecisionVoter.ACCESS_GRANTED;
            }
        }
        return result;
    }
}

3.3. 配置remember-me、session

在web.xml中配置remember-me和session的过期时间。

<session-config>
        <session-timeout>30</session-timeout>
    </session-config>

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>RememberMeFilter</filter-name>
        <filter-class>org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>RememberMeFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

3.4. 配置SecurityConfig

最后,在Spring Security的配置文件SecurityConfig.java中,我们要做两件事情:

  1. 配置自定义权限管理器。
  2. 指定需要进行方法安全拦截的package,并且指定自定义投票验证器。

示例代码:

@Configuration
@EnableWebSecurity
@ComponentScan(basePackages = {"com.example.demo"})
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomAccessDecisionManager customAccessDecisionManager;

    @Autowired
    private UrlAccessDecisionVoter urlAccessDecisionVoter;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .antMatchers("/user/**").hasRole("USER")
                .anyRequest().authenticated()
                .and()
                .formLogin().loginPage("/login").permitAll()
                .and()
               .logout().logoutUrl("/logout").permitAll()
               .and()
                .exceptionHandling().accessDeniedPage("/noAuth");

    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
        web.ignoring().antMatchers("/css/**", "/js/**");
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("admin").password("123456").roles("ADMIN", "USER")
                .and()
                .withUser("user").password("123456").roles("USER");
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
        web.ignoring().antMatchers("/css/**", "/js/**");
    }

    @Bean
    public FilterRegistrationBean<Filter> registrationBean() {
        FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new DelegatingFilterProxy());
        registrationBean.addUrlPatterns("/*");
        registrationBean.setName("springSecurityFilterChain");
        return registrationBean;
    }

    @Bean
    public AccessDecisionManager accessDecisionManager() {
        List<AccessDecisionVoter<?>> decisionVoters = new ArrayList<>();
        decisionVoters.add(urlAccessDecisionVoter);
        //这里可以按照自己需求添加更多的投票器
        AffirmativeBased accessDecisionManager = new AffirmativeBased(decisionVoters);
        accessDecisionManager.setDecisionVoters(decisionVoters);
        return customAccessDecisionManager;
    }
}

4. 示例

下面是两个基于Spring Security动态授权的示例:

4.1. 部分接口只允许admin角色访问

在上面的代码中,我们在SecurityConfig.java中配置了urlAccessDecisionVoter,用于具体控制某些URL只允许admin角色访问。

我们可以使用这个功能来控制某些URL,比如在员工管理系统中,启用了一个特殊的功能模块,只允许部门经理和人事经理访问员工数据。

代码:

@GetMapping("/employee/list")
    @Log(title = "员工管理", businessType = BusinessType.LIST)
    public AjaxResult<List<Employee>> getEmployeeList() {
        return ajaxResponse(employeeService.getAllEmployees());
    }

    @PostMapping("/employee/add")
    @Log(title = "员工管理", businessType = BusinessType.INSERT)
    public AjaxResult<String> addEmployee(@RequestBody Employee employee) {
        if(employeeService.addEmployee(employee) == 0) {
            return ajaxFailed("添加员工失败,请检查员工信息后重试");
        }
        return ajaxResponse("添加员工成功!");
    }

4.2. 个别接口不需要权限控制,直接访问

如果一个URL的访问权限比较低,比如说是一个报道页面,或者是一个新闻页面,我们可以让它不受权限管理器的控制,直接访问。

5. 总结

以上就是Spring Security权限管理实现接口动态权限控制的完整攻略,通过实现AccessDecisionManager接口和AccessDecisionVoter接口,可以实现对接口的权限控制。动态授权功能可以根据不同的需求对用户进行权限管理,灵活性很高。

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

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • 什么是类路径?

    以下是关于类路径的完整使用攻略: 什么是类路径? 类路径是Java虚拟机(JVM)用来查找类文件的路径。当JVM需要加载一个类时它会在类路径中查找该类的字节码文件。类路径可以包含多个路径,每个路径之间用分隔符(如冒号或分号)分隔。 类路径的设置 类路径可以通过以下方式进行设置: 命令行参数:可以通过命令行参数设置类路径。例如,以下是一个设置类路径的命令: b…

    Java 2023年5月12日
    00
  • java实现猜拳游戏试题

    下面我将详细讲解“java实现猜拳游戏试题”的完整攻略。 1. 确定游戏规则 在开始编写程序之前,需要先确定猜拳游戏的规则。通常猜拳游戏有剪刀、石头和布三种手势,其中剪刀克制布,布克制石头,石头克制剪刀。参与游戏的两个玩家选择其中一种手势,如果两个玩家选择的手势相同,则为平局;否则根据手势的胜负关系判断胜负,并输出胜负结果。 2. 编写程序 2.1. 实现游…

    Java 2023年5月23日
    00
  • Java Web中ServletContext对象详解与应用

    下面我将为你详细讲解Java Web中ServletContext对象的完整攻略。 什么是ServletContext对象 ServletContext是Java Web容器中的一个重要对象,它代表整个Web应用程序,一个Web应用程序只有一个ServletContext对象。ServletContext对象在Web应用程序启动时被创建,在Web应用程序停止…

    Java 2023年6月15日
    00
  • Java数组归纳总结

    Java数组归纳总结 在Java语言中,数组是一种非常常用的数据结构,可以用来存储同一类型的数据。本文将对Java数组进行归纳总结,包括数组的定义、初始化、遍历、复制、排序等常用操作,以及一些常见问题和解决方案。 数组的定义 Java数组是一种固定长度的数据结构,可以存储同一类型的数据。数组定义时需要指定数组的长度和类型。 声明一个长度为10,类型为int的…

    Java 2023年5月26日
    00
  • SpringMVC实现文件上传和下载功能

    SpringMVC实现文件上传和下载功能 Spring MVC提供了很好的机制来实现文件上传和下载功能,但需要借助一些依赖包和配置设置。 1. 添加MultipartResolver Bean 在Spring MVC应用中,我们需要添加一个MultipartResolver Bean以处理文件上传的请求。MultipartResolver 接口定义了文件上传…

    Java 2023年6月15日
    00
  • java加载properties文件的六种方法总结

    以下是讲解“java加载properties文件的六种方法总结”的完整攻略。 一、背景 在Java应用中经常会使用配置文件properties来存储一些固定的配置信息,方便程序在运行时读取。那么在Java中如何加载properties文件呢?本文将总结6种Java加载properties文件的方法。 二、直接使用Java代码加载 直接使用Java代码加载pr…

    Java 2023年5月20日
    00
  • Java线程休眠的5种方法

    Java线程休眠的5种方法 Java中的线程可以通过休眠来暂停一段时间。线程的休眠有5种方法,本文将详细介绍这5种方法,并给出代码示例。 方法一:使用Thread.sleep() Thread.sleep()是Java中比较常用的线程休眠方法。它可以将当前正在执行的线程休眠指定的时间,单位是毫秒。下面是使用Thread.sleep()方法的示例: publi…

    Java 2023年5月19日
    00
  • Springmvc数据格式化原理及代码案例

    SpringMVC数据格式化原理及代码案例 在SpringMVC中,我们可以使用数据格式化器来将请求参数转换为Java对象或将Java对象转换为响应参数。本文将详细讲解SpringMVC数据格式化的原理及代码案例。 数据格式化原理 SpringMVC的数据格式化器是通过实现Converter接口或Formatter接口来实现的。Converter接口用于将一…

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