如何在Spring Security中动态决定<intercept-url>访问属性值?

Cra*_*ker 26 authorization spring-security security-roles

在Spring Security中,我们使用intercept-url标记来定义URL的访问权限,如下所示:

<intercept-url pattern="/**" access="ROLE_ADMIN" />
<intercept-url pattern="/student" access="ROLE_STUDENT" />
Run Code Online (Sandbox Code Playgroud)

这是硬编码的applicationContext-security.xml.我想从数据库表中读取访问值.我已经定义了自己的UserDetailsService,我从数据库中读取了登录用户的角色.如何在运行时将这些角色分配给URL模式?

jbb*_*ero 21

Spring-security中的FilterInvocationSecurityMetadataSourceParser类(使用源代码在STS中尝试Ctrl/Cmd + Shift + T)解析intercept-url标记并创建ExpressionBasedFilterInvocationSecurityMetadataSource的实例,该实例扩展了实现扩展SecurityMetadataSource的FilterInvocationSecurityMetadataSource的DefaultFilterInvocationSecurityMetadataSource.

我所做的是创建一个实现FilterInvocationSecurityMetadataSource,OptionsFromDataBaseFilterInvocationSecurityMetadataSource的自定义类.我用DefaultFilterInvocationSecurityMetadataSource作为基地使用urlMatcher,落实支持()方法和类似的东西.

然后你必须实现这些方法:

  • 集合getAttributes(Object object),您可以在其中访问数据库,搜索受保护的"对象"(通常是访问的URL)以获取允许的ConfigAttribute(通常是ROLE的)

  • 布尔支持(类clazz)

  • 集合getAllConfigAttributes()

小心后面的,因为它在启动时被调用,并且可能在此时配置不正确(我的意思是,数据源或持久性上下文自动装配,取决于你使用的是什么).Web环境中的解决方案是在web.xml中配置contextConfigLocation以在applicationContext-security.xml之前加载applicationContext.xml

最后一步是自定义applicationContext-security.xml以加载此bean.

为此,我在此文件中使用常规bean而不是安全命名空间:

    <beans:bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
    <filter-chain-map path-type="ant">
        <filter-chain pattern="/images/*" filters="none" />
        <filter-chain pattern="/resources/**" filters="none" />
        <filter-chain pattern="/**" filters="
        securityContextPersistenceFilter,
        logoutFilter,
        basicAuthenticationFilter,
        exceptionTranslationFilter,
        filterSecurityInterceptor" 
    />
    </filter-chain-map>
</beans:bean>
Run Code Online (Sandbox Code Playgroud)

您必须定义所有相关的bean.例如:

    <beans:bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
    <beans:property name="authenticationManager" ref="authenticationManager"></beans:property>
    <beans:property name="accessDecisionManager" ref="affirmativeBased"></beans:property>
    <beans:property name="securityMetadataSource" ref="optionsFromDataBaseFilterInvocationSecurityMetadataSource"></beans:property>
    <beans:property name="validateConfigAttributes" value="true"/></beans:bean>
Run Code Online (Sandbox Code Playgroud)

我知道这不是一个很好解释的答案,但它并不像看起来那么困难.

只需使用弹簧源作为基础,您就可以获得所需的效果.

使用数据库中的数据进行调试将对您有所帮助.