Spring Security动态权限验证

spring | 2023-05-13 22:04:25
@Configuration
public class WebSerurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserServiceImpl userService;
    @Autowired
    private MyFilter filter;
    @Autowired
    private RoleAccessDecisionManager roleAccessDecisionManager;

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/student/**").hasRole("student")
                .antMatchers("/teacher/**").hasRole("teacher")
                .antMatchers("/admin/**").hasRole("admin")
                .anyRequest().authenticated()
        .and().formLogin().permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
          ...
    }
}

 

从代码中,我们可以看到,每次我们添加一个角色,就需要添加角色所对应的权限路径。当我们有越来越多的角色时,我们需要不断往我们的代码中进行添加,这样做显然是很不好的。所以,接下来,我们要把角色和路径都写在数据库中,当我们添加一个角色或者修改角色对应的权限路径时,只需要往数据库进行修改即可。

1.获取当前路径所对应的全部权限(角色)
将问题进行细分:

获取当前请求路径url
获取数据库全部有权限(角色)的url
将当前请求url跟数据库中的url进行对比
(1)如果在数据库中,就要获取当前请求对应的权限(角色)
(2)如果不在,则不用返回权限信息。
getAttributes()方法:返回本次访问需要的权限,可以有多个权限。

@Component
public class MyFilter implements FilterInvocationSecurityMetadataSource {
    @Autowired
    private UrlMapper urlMapper;

    AntPathMatcher antPathMatcher = new AntPathMatcher();

    /  //获取当前url对应的权限
    @Override
    public Collection getAttributes(Object o) throws IllegalArgumentException {
       //1.获取当前url
        String requestUrl = ((FilterInvocation) o).getRequestUrl();
        //2.获取数据库
        List allPath = pathMapper.getAllPath();
        //3.判断当前url和allPath是否匹配
        for (Path path : allPath) {
            if(new AntPathMatcher().match(path.getPattern(),requestUrl)){
                //4.如果匹配上了,获取这个路径的权限
                List rolesList = roleMapper.getRolesByPid(path.getId());
                //5.返回出去
                String [] rs = new String[rolesList.size()];
                for (int i = 0; i < rolesList.size(); i++) {
                    rs[i] = rolesList.get(i).getRname();
                }
                return SecurityConfig.createList(rs);
            }
        }
       return null;
    }

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

    @Override
    public boolean supports(Class aClass) {
        return true;
    }
}

 

2.权限决策(获取当前用户所对应的权限)


有了权限资源,知道了当前访问的url所需要的具体权限,接下来就是决策当前的访问是否能够通过权限验证了。
AccessDecisionManager:决策管理器
实现AccessDecisionManager接口,自定义决策管理器。

decide()方法有三个参数:

authentication: 当前用户对应的信息
object:包含客户端发起的请求的requset信息
collection 当前路径对应的权限
判断该用户对应的权限信息是否跟当前路径对应的权限信息相等。
 

@Component
public class RoleAccessDecisionManager implements AccessDecisionManager {


    /**
     * decide 方法是判定是否拥有权限的决策方法,
     * @param authentication 当前用户的信息
     * @param object 包含客户端发起的请求的requset信息
     * @param collection  当前路径对应的权限
     * @throws AccessDeniedException
     * @throws InsufficientAuthenticationException
     */
    @Override
    public void decide(Authentication authentication, Object object, Collection collection) throws AccessDeniedException, InsufficientAuthenticationException {
        Collection authorities = authentication.getAuthorities();
        for (GrantedAuthority authority : authorities) {
            for (ConfigAttribute c : collection) {
                if(c.getAttribute().equals(authority.getAuthority())){
                    return;
                }
            }
        }

        throw new AccessDeniedException("当前访问没有权限");
    }

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

    @Override
    public boolean supports(Class aClass) {
        return true;
    }
}

 

3.在WebSerurityConfig.java进行配置

@Configuration
public class WebSerurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserServiceImpl userService;
    @Autowired
    private MyFilter filter;
    @Autowired
    private RoleAccessDecisionManager roleAccessDecisionManager;

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                 .withObjectPostProcessor(new ObjectPostProcessor() {
                     @Override
                     public  O postProcess(O o) {
                         o.setAccessDecisionManager(roleAccessDecisionManager);
                         o.setSecurityMetadataSource(filter);
                         return o;
                     }
                 })
//                .antMatchers("/student/**").hasRole("student")
//                .antMatchers("/teacher/**").hasRole("teacher")
//                .antMatchers("/admin/**").hasRole("admin")
                .anyRequest().authenticated()
        .and().formLogin().permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        auth.inMemoryAuthentication().
//                withUser("msj").password(passwordEncoder().encode("msj")).roles("student");
        auth.userDetailsService(userService);
    }
}

 

 

登录后即可回复 登录 | 注册
    
关注编程学问公众号