升级弹簧安全性从3.2升级到4.0.2后,PreAuthorized(" hasRole()")总是返回false

时间:2015-10-22 20:11:04

标签: spring spring-security

从版本3.2.x升级spring-security到版本4.0.2后,我能够登录到Web应用程序,但是如果它尝试访问具有@PreAuthorized(hasRole)的方法,则会拒绝访问())。

我试图注入' ROLE _'进入GrantAuthorities列表,但结果是一样的。

相同的配置在版本3.2.x中正常工作。谁能知道我做错了什么?

由于

security-context.xml

<http pattern="/css/**" security="none" />
<http pattern="/Images/**" security="none" />
<http pattern="/javascript/**" security="none" />

<http auto-config='true' use-expressions="true" create-session="always"
    authentication-manager-ref="tunAuthenticationManager">
    <csrf disabled="true" />

    <intercept-url pattern="/new/**"
        access="hasRole('eu_rw') or hasRole('sp_rw')" />
    <intercept-url pattern="/ajax/**"
        access="hasRole('eu_rw') or hasRole('sp_rw')" />
    <intercept-url pattern="/v2/**"
        access="hasRole('eu_rw') or hasRole('sp_rw')" />

    <intercept-url pattern="/monitoring" access="hasRole('sp_rw')" />
    <intercept-url pattern="/monitoring/**" access="hasRole('sp_rw')" />

    <form-login login-page="/logon.jsp" username-parameter="username"
        password-parameter="password" login-processing-url="/j_spring_security_check"
        authentication-failure-url="/logon.jsp?login_error=1"
        default-target-url="/" always-use-default-target="true" />

    <custom-filter position="FIRST" ref="logoutFilter" />
    <custom-filter after="FIRST" ref="requestLoggingFilter" />
    <custom-filter after="LAST" ref="passwordExpirationCheckFilter" />
    <custom-filter after="SWITCH_USER_FILTER" ref="authorizationAdjustmentFilter" />
    <custom-filter after="EXCEPTION_TRANSLATION_FILTER" ref="ajaxTimeoutRedirectFilter" />
</http>



<authentication-manager id="tunAuthenticationManager">
    <authentication-provider ref="strongDaoAuthenticationProviderProxy" />
    <authentication-provider ref="tunAdAuthenticationProvider" />
</authentication-manager>

<beans:bean id="strongDaoAuthenticationProviderProxy"
    class="local.company.tun.security.DaoAuthenticationProviderProxy">
    <beans:constructor-arg>
        <beans:bean id="strongDaoAuthenticationProvider"
            class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
            <beans:property name="userDetailsService" ref="jdbcUserDetailsService" />
            <beans:property name="passwordEncoder" ref="strongEncoder" />
            <beans:property name="saltSource" ref="saltSource" />
        </beans:bean>
    </beans:constructor-arg>
</beans:bean>
<beans:bean id="jdbcUserDetailsService"
    class="local.company.tun.security.tunUserDetailsService">
</beans:bean>
<beans:bean id="authenticationService"
    class="local.company.tun.security.service.impl.AuthenticationServiceImpl">
    <beans:qualifier value="authenticationService" />
    <beans:property name="authenticationManager" ref="tunAuthenticationManager" />
</beans:bean>
<beans:bean
    class="local.company.tun.security.DefaultRolesPrefixPostProcessor" />

servlet的context.xml中

<mvc:interceptors>
    <!-- Changes the locale when a 'locale' request parameter is sent;
        e.g. /?locale=de -->
        <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
</mvc:interceptors>

<!-- Activate scanning of @Autowired -->
<context:annotation-config />
<!-- Spring Security - enable pre- post- annotations on Spring managed
    MVC components -->
<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler" >

</bean>
<security:global-method-security pre-post-annotations="enabled">
    <security:expression-handler ref="expressionHandler" />
</security:global-method-security>

...

3 个答案:

答案 0 :(得分:2)

您必须在角色名称中使用ROLE_前缀,并在GrantedAuthorities中使用相同的内容,否则除非您将前缀设置为空,否则它将无效。

RoleVoter.setRolePrefix(""); 


@PreAuthorize("hasRole('ROLE_ADMIN')")

new SimpleGrantedAuthority("ROLE_ADMIN")

还有一个想法如何调试。在userDetails.getAuthorities()方法中加上一个断点。然后访问受保护的资源。 Spring将检查权限的实际版本并将被捕获。向上浏览堆栈跟踪,找到比较的地点和值,找出问题所在。

答案 1 :(得分:1)

我可以通过添加

来解决此问题
<beans:bean
class="local.company.tun.security.DefaultRolesPrefixPostProcessor" />

到security-context.xml和servlet-context.xml。看起来两个地方都需要它。 security-context.xml中的bean将阻止添加&#34; ROLE _&#34;到了 servlet-context.xml中的bean将阻止添加&#34; ROLE _&#34;到了 方法水平。

作为参考,DefaultRolePrefixPostProcessor.java是来自spring security migration 3的复制 - &gt; 4.这里是完整性的源代码。

公共类DefaultRolesPrefixPostProcessor实现BeanPostProcessor,PriorityOrdered {

@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
        throws BeansException {

    Logger logger = LoggerFactory.getLogger(DefaultRolesPrefixPostProcessor.class);
    // remove this if you are not using JSR-250
    if(bean instanceof Jsr250MethodSecurityMetadataSource) {
        ((Jsr250MethodSecurityMetadataSource) bean).setDefaultRolePrefix(null);
    }

    if(bean instanceof DefaultMethodSecurityExpressionHandler) {
        logger.info("overriding the default Role prefix. set it to null ");
        ((DefaultMethodSecurityExpressionHandler) bean).setDefaultRolePrefix(null);
    }
    if(bean instanceof DefaultWebSecurityExpressionHandler) {
        ((DefaultWebSecurityExpressionHandler) bean).setDefaultRolePrefix(null);
    }
    if(bean instanceof SecurityContextHolderAwareRequestFilter) {
        ((SecurityContextHolderAwareRequestFilter)bean).setRolePrefix("");
    }
    return bean;
}

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
        throws BeansException {
    return bean;
}

@Override
public int getOrder() {
    return PriorityOrdered.HIGHEST_PRECEDENCE;
}

}

答案 2 :(得分:0)

您可以使用hasAuthority()代替hasRole(),hasAuthority()不会附加defaultRolePrefix。另外,您也可以将其添加到security-context.xml中,以将defaultRolePrefix覆盖为null:

<!-- Remove defaultRolePrefix from SecurityExpressionRoot.java to prevent hasRole() call from appending "ROLE_" to role parameters -->
<bean id="defaultWebSecurityExpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler">
    <property name="defaultRolePrefix" value=""></property>
</bean>

<bean id="defaultMethodSecurityExpressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
    <property name="defaultRolePrefix" value=""></property>
</bean>

<security:global-method-security pre-post-annotations="enabled">
    <security:expression-handler ref="defaultMethodSecurityExpressionHandler" />
</security:global-method-security>

参考文章:Why does Spring Security's RoleVoter need a prefix?