springsecurity动态配置url权限如何实现?

TheDisguiser 2020-08-09 22:04:26 java常见问答 6168

springsecurity如何动态配置url权限呢?如果还需要自己手动配置就太那个了,下面来看看动态是如何实现的。

在spring security中,有着各种内置的filter,这里我们来重写一下SecurityMetadataSource用以动态获取url权限配置,再用AccessDecisionManager进行权限判断。

MyAccessDecisionManager

public class MyAccessDecisionManager implements org.springframework.security.access.AccessDecisionManager
{
    @Override
    public void decide(Authentication authentication, Object object
        , Collection < ConfigAttribute > configAttributes)
    throws AccessDeniedException, InsufficientAuthenticationException
    {        
        if (CollectionUtils.isEmpty(configAttributes))
        {
            throw new AccessDeniedException("not allow");
        }
        Iterator < ConfigAttribute > ite = configAttributes.iterator();
        while (ite.hasNext())
        {
            ConfigAttribute ca = ite.next();
            String needRole = ((org.springframework.security.access.SecurityConfig) ca)
                .getAttribute();
            for (GrantedAuthority ga: authentication.getAuthorities())
            {
                if (ga.getAuthority()
                    .equals(needRole))
                {
                    //匹配到有对应角色,则允许通过
                    return;
                }
            }
        }
        //该url有配置权限,但是当然登录用户没有匹配到对应权限,则禁止访问
        throw new AccessDeniedException("not allow");
    }
    @Override
    public boolean supports(ConfigAttribute attribute)
    {
        return true;
    }
    @Override
    public boolean supports(Class < ? > clazz)
    {
        return true;
    }
}

上面我们看到会遍历判断出这个url所需的角色看用户是否具备,具备就返回,否则就抛出AccessDeniedException异常

MyFilterInvocationSecurityMetadataSource

public class MyFilterInvocationSecurityMetadataSource implements org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource
{
    private final AntPathMatcher antPathMatcher = new AntPathMatcher();
    private final Map < String, String > urlRoleMap = new HashMap < String, String > ()
    {
        {
            put("/open/**", "ROLE_ANONYMOUS");
            put("/health", "ROLE_ANONYMOUS");
            put("/restart", "ROLE_ADMIN");
            put("/demo", "ROLE_USER");
        }
    };
    @Override
    public Collection < ConfigAttribute > getAttributes(Object object) throws IllegalArgumentException
    {
        FilterInvocation fi = (FilterInvocation) object;
        String url = fi.getRequestUrl();
        //        String httpMethod = fi.getRequest().getMethod();
        for (Map.Entry < String, String > entry: urlRoleMap.entrySet())
        {
            if (antPathMatcher.match(entry.getKey(), url))
            {
                return SecurityConfig.createList(entry.getValue());
            }
        }
        //没有匹配到,默认是要登录才能访问
        return SecurityConfig.createList("ROLE_USER");
        //        return null;
    }
    @Override
    public Collection < ConfigAttribute > getAllConfigAttributes()
    {
        return null;
    }
    @Override
    public boolean supports(Class < ? > clazz)
    {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}

这里我们以内存的map来show一下,实际应用是可以从分布式配置中心或数据库中读取的。

SecurityConfig

再来综合配置下,如:

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
    @Override
    public void configure(HttpSecurity http) throws Exception
    {
        http
            .authorizeRequests()
            .anyRequest()
            .authenticated()
            .withObjectPostProcessor(new ObjectPostProcessor < FilterSecurityInterceptor > ()
            {
                public < O extends FilterSecurityInterceptor > O postProcess(
                    O fsi)
                {
                    fsi.setSecurityMetadataSource(mySecurityMetadataSource());
                    fsi.setAccessDecisionManager(myAccessDecisionManager());
                    return fsi;
                }
            });
    }
    @Bean
    public FilterInvocationSecurityMetadataSource mySecurityMetadataSource()
    {
        MyFilterInvocationSecurityMetadataSource securityMetadataSource = new MyFilterInvocationSecurityMetadataSource();
        return securityMetadataSource;
    }
    @Bean
    public AccessDecisionManager myAccessDecisionManager()
    {
        return new MyAccessDecisionManager();
    }
}

以上就是本篇文章的所有内容,对java架构师还有不懂得的知识的话,可以来我们网站查询答案。

推荐阅读:

springsecurity两套登陆规则是什么?springsecurity详解

springsecurity权限控制的原理是如何实现的?

springsecurity面试题常见有哪些?