Spring Security 3.2.6.RELEASE 升级到 4.2.3.RELEASE 踩了些坑,记录一下:
1、ifAnyGranted标签取消,使用<sec:authorize access="hasAnyRole('ROLE_ADMIN','ROLE_USER')">代替。
2、登录表单字段名修改:
j_username -> username
j_password -> password
_spring_security_remember_me -> remember-me
3、登陆后出现 Could not verify the provided CSRF token because your CSRF session was not found
这是因为spring security为了防止跨站请求做的.如果需要关闭那么在security:http下添加一个子标签<security:csrf disabled="true" />
4、Spring Security中角色前缀rolePrefix默认为“ROLE_”,如果要修改的话Spring Security 3 只需要实例化RoleVoter时设置rolePrefix属性即可,升级后发现标签access="hasAnyRole('A_ADMIN','A_USER')"失效,调试发现Spring Security 4.2 中还需要实例化org.springframework.security.config.core.GrantedAuthorityDefaults并设置rolePrefix属性,该类是4.2新增的。
<!-- 授权判断配置, 将授权名称的默认前缀由ROLE_改为A_. -->
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<constructor-arg>
<list>
<bean class="org.springframework.security.access.vote.RoleVoter">
<property name="rolePrefix" value="A_" />
</bean>
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</list>
</constructor-arg>
<property name="allowIfAllAbstainDecisions" value="false"></property>
</bean>
<!-- SpringSecurity4 下修改rolePrefix 与RoleVoter中的rolePrefix保持一致-->
<bean class="org.springframework.security.config.core.GrantedAuthorityDefaults">
<constructor-arg>
<value>A_</value>
</constructor-arg>
</bean>
调试过程如下:
hasAnyRole实际调用了抽象类org.springframework.security.access.expression.SecurityExpressionRoot的hasAnyRole方法
而其实现类WebSecurityExpressionRoot的创建在org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler中
而SecurityExpressionHandler的获取是在JspAuthorizeTag的父类AbstractAuthorizeTag的getExpressionHandler方法
可见SecurityExpressionHandler的实例是org.springframework.security.config.http.FilterInvocationSecurityMetadataSourceParser中的静态内部类DefaultWebSecurityExpressionHandlerBeanFactory,而该类继承自GrantedAuthorityDefaultsParserUtils.AbstractGrantedAuthorityDefaultsBeanFactory
这里“this.rolePrefix”即是AbstractGrantedAuthorityDefaultsBeanFactory中的属性
AbstractGrantedAuthorityDefaultsBeanFactory子类在实例化注入applicationContext的时候会查找是否有GrantedAuthorityDefaults的实例,如果有的话就获取GrantedAuthorityDefaults实例的rolePrefix属性来更新自己的rolePrefix属性,从而实现更改前缀的目的。
参考资料:https://docs.spring.io/spring-security/site/migrate/current/3-to-4/html5/migrate-3-to-4-xml.html