SpringBoot Spring Security XML转Java配置后/login无访问权限问题
Spring迁移SpringBoot时Spring Security配置导致/login无权限问题
问题背景
正在开展Spring至SpringBoot的项目迁移工作,需将原有Spring项目中的secure.xml安全配置转换为对应的Spring Security Java配置类,迁移后访问/login路径时提示无访问权限,将对应路径规则替换为permitAll()后登录页可正常加载,需要定位配置错误原因。
原有secure.xml配置
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd"> <http auto-config="true" use-expressions="true" pattern="/login"> <csrf disabled="true" /> </http> <http auto-config="true" use-expressions="true" pattern="/abc/la/**"> <csrf disabled="true" /> </http> <http auto-config="true"> <intercept-url pattern="/resources/**" access="hasAnyRole('ROLE_ANONYMOUS','ROLE_ADMIN','ROLE_USER')" /> <intercept-url pattern="/login" access="hasAnyRole('ROLE_ANONYMOUS','ROLE_ADMIN','ROLE_USER')" /> <intercept-url pattern="/abc/**" access="hasAnyRole('ROLE_ANONYMOUS','ROLE_ADMIN','ROLE_USER')" /> <intercept-url pattern="/**" access="hasAnyRole('ROLE_ADMIN','ROLE_USER')" /> <form-login login-page="/login" default-target-url="/login" authentication-failure-url="/login" username-parameter="username" password-parameter="password" /> <logout logout-success-url="/logout" /> </http> <authentication-manager alias="authenticationManager"> <authentication-provider ref="customAuthenticationProvider" /> </authentication-manager> <beans:bean id="customAuthenticationProvider" class="com.foo.CustomAuthenticationProvider" /> <beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"> <beans:constructor-arg name="strength" value="6" /> </beans:bean> </beans:beans>
初始编写的Java配置类
@Configuration @EnableWebSecurity public class CustomSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired CustomAuthenticationProvider customAuthenticationProvider; @Override protected void configure(HttpSecurity http) throws Exception{ http.csrf().disable().authorizeHttpRequests().antMatchers("/login").hasAnyRole("ANONYMOUS","ADMIN","USER"); http.csrf().disable().authorizeHttpRequests().antMatchers("/abc/la/**").hasAnyRole("ANONYMOUS","ADMIN","USER"); http .authorizeRequests() .antMatchers("/login").hasAnyRole("ANONYMOUS","ADMIN","USER") .antMatchers("/logout").hasAnyRole("ANONYMOUS","ADMIN","USER") .antMatchers("/resources/**").hasAnyRole("ANONYMOUS","ADMIN","USER") .antMatchers("/abc/**").hasAnyRole("ANONYMOUS","ADMIN","USER") .antMatchers("/**").hasAnyRole("ADMIN","USER") .and() .formLogin() .loginPage("/login") .failureUrl("/login") .usernameParameter("username") .passwordParameter("password"); http.logout().logoutSuccessUrl("/logout");; } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception{ auth.authenticationProvider(customAuthenticationProvider); } @Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(6); } }
问题表现
- 访问
/login路径时提示 You don't have authorization to view this page.,无访问权限
- 将以下配置规则:
.antMatchers("/login").hasAnyRole("ANONYMOUS","ADMIN","USER") .antMatchers("/logout").hasAnyRole("ANONYMOUS","ADMIN","USER") .antMatchers("/resources/**").hasAnyRole("ANONYMOUS","ADMIN","USER")
替换为permitAll()规则后,登录页即可正常加载:
.antMatchers("/login").permitAll() .antMatchers("/logout").permitAll() .antMatchers("/resources/**").permitAll()
问题原因
你的Java配置存在两处核心错误,导致和原有XML配置逻辑不一致:
- 匿名用户权限配置逻辑错误
ROLE_ANONYMOUS是Spring Security为未登录用户分配的内部身份标识,不属于普通业务角色:- Java配置中
hasAnyRole()方法会自动为传入的角色值拼接ROLE_前缀,你传入ANONYMOUS时,实际校验的角色是ROLE_ANONYMOUS,但匿名用户的权限校验有专门的方法,直接作为普通角色匹配在SpringBoot集成的高版本Spring Security中存在逻辑冲突,无法正常匹配未登录用户身份。 - 对于登录页、静态资源这类所有用户都可访问的路径,正确的配置方式是使用
permitAll(),而非尝试匹配匿名角色。
- Java配置中
- 多安全过滤链配置方式错误
原有XML中多个独立的<http>标签会生成多个按顺序匹配的安全过滤链,优先级高的路径先匹配。但你在Java配置中多次操作同一个HttpSecurity实例,前两行针对/login、/abc/la/**的配置会被后续的配置覆盖,根本不会生效,所有请求都会走后面定义的权限规则。
修正后的配置
@Configuration @EnableWebSecurity public class CustomSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired CustomAuthenticationProvider customAuthenticationProvider; @Override protected void configure(HttpSecurity http) throws Exception{ http // 全局关闭csrf,和原有XML配置一致 .csrf().disable() .authorizeRequests() // 公开路径直接放行 .antMatchers("/login", "/logout", "/resources/**", "/abc/**").permitAll() // 其余路径需要登录后拥有ADMIN/USER角色才可访问 .antMatchers("/**").hasAnyRole("ADMIN","USER") .and() .formLogin() .loginPage("/login") .defaultSuccessUrl("/login") .failureUrl("/login") .usernameParameter("username") .passwordParameter("password") .and() .logout() .logoutSuccessUrl("/logout"); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception{ auth.authenticationProvider(customAuthenticationProvider); } @Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(6); } }
注:如果你需要保留原有XML中针对
/login、/abc/la/**的独立过滤链逻辑,需要定义多个SecurityFilterChainBean并指定@Order优先级,不要在同一个HttpSecurity配置中重复定义相同路径的规则。
内容的提问来源于stack exchange,提问作者Ravi
相关产品推荐
相关产品推荐

