13、Spring Security 实战 - 数据库方式配置用户

前言

前面权限配置介绍了两种方式,一种是基于注解的权限配置,一种是基于配置文件的权限配置。虽然两种方式都可以实现权限拦截,但是基于注解的方式每个方法上都要添加注解,太过于分散,不好管理;而基于配置文件的方式,虽然可以将所有的配置在配置文件中配置,但是每次添加接口都要在相应的配置类中添加配置,而且没法跟数据库关联起来。接下来,进行优化。

实现

创建授权AccessInterception类,实现FilterInvocationSecurityMetadataSource接口;主要作用是将当前请求需要的权限返回。

@Component
public class AccessInterception implements FilterInvocationSecurityMetadataSource {
   
     
    @Autowired
    SysMenuService sysMenuService;

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
   
     
        String requestUrl = ((FilterInvocation) object).getRequestUrl();
        List<SysMenu> sysMenus = sysMenuService.list();
        for (SysMenu sysMenu : sysMenus) {
   
     
            if (new AntPathMatcher().match(sysMenu.getUrl(), requestUrl)) {
   
     
                return SecurityConfig.createList(sysMenu.getUrl());
            }
        }
        return SecurityConfig.createList("/login");
    }

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

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

创建AccessDecision类实现AccessDecisionManager,决策管理的主要作用是进行对当前请求是否通过进行决策。

@Component
public class AccessDecision implements AccessDecisionManager {
   
     
    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
            throws AccessDeniedException, InsufficientAuthenticationException {
   
     
        for (ConfigAttribute configAttribute : configAttributes) {
   
     
            String attribute = configAttribute.getAttribute();
            if ("/login".equals(attribute)) {
   
     
                if (authentication instanceof AnonymousAuthenticationToken) {
   
     
                    throw new InsufficientAuthenticationException(ResultCode.NOT_SIGN_IN.getMessage());
                } else {
   
     
                    return;
                }
            }
            Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
            for (GrantedAuthority authority : authorities) {
   
     
                if (authority.getAuthority().equals(attribute)) {
   
     
                    return;
                }
            }
        }
        throw new AccessDeniedException(ResultCode.NO_PERMISSION.getMessage());
    }

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

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

SpringSecurityConfig 中添加以下bean,并将上面两个bean设置到FilterSecurityInterceptor中。

@Bean
FilterSecurityInterceptor filterSecurityInterceptor() {

 
    FilterSecurityInterceptor filterSecurityInterceptor = new FilterSecurityInterceptor();
    filterSecurityInterceptor.setAccessDecisionManager(accessDecision);
    filterSecurityInterceptor.setSecurityMetadataSource(accessInterception);
    return filterSecurityInterceptor;
}

然后将我们的FilterSecurityInterceptor放到原有FilterSecurityInterceptor中。

 http.addFilterAt(filterSecurityInterceptor(), FilterSecurityInterceptor.class);

将之前写死的路径匹配注释起来

//        http.authorizeRequests()
//                .antMatchers("/sys/user/list").hasAuthority("/sys/user/list")
//                .antMatchers("/sys/user/query").hasAuthority("/sys/user/query")
//                .anyRequest().authenticated();

验证

启动项目进行验证,user用户只有list权限,admin拥有list和query权限