我正在尝试将一个应用程序更新到 Boot ,它将SpringSecurity升级到了5.7,并弃用了WebSecurityConfigurerAdapter
。
下面是旧代码的一个简化版本,它创建一个用户,并且可以工作。注意,这个代码只用于本地开发和测试,使用一个简单的表单登录:
@Configuration
@Profile("local-auth")
class LocalAuth {
@Bean
public WebSecurityConfigurerAdapter webSecurityConfigurerAdapter(
PasswordEncoder passwordEncoder) {
return new WebSecurityConfigurerAdapter() {
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("testuser")
.password(passwordEncoder.encode("a"))
.authorities(toAuthorities(List.of("SOME_AUTHORITY")));
}
private List<? extends GrantedAuthority> toAuthorities(List<String> roles) {
return roles.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorizeRequests ->
authorizeRequests
.antMatchers("/login", "/actuator/**", "/publico/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(formLogin -> formLogin.defaultSuccessUrl("http://localhost:4200/app/").permitAll())
.logout(logout -> logout.logoutUrl("/logout"))
.csrf(AbstractHttpConfigurer::disable);
}
};
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
按照https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter处的指南,我将代码更改为
@Configuration
@Profile("local-auth")
class LocalAuth {
@Bean
public InMemoryUserDetailsManager userDetailService(PasswordEncoder passwordEncoder) {
UserDetails user = User.builder()
.username("testuser")
.password(passwordEncoder.encode("a"))
.authorities(toAuthorities(List.of("SOME_AUTHORITY")))
.build();
return new InMemoryUserDetailsManager(user);
}
private List<? extends GrantedAuthority> toAuthorities(List<String> roles) {
return roles.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorizeRequests ->
authorizeRequests
.antMatchers("/login", "/actuator/**", "/publico/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(formLogin -> formLogin.defaultSuccessUrl("http://localhost:4200/app/").permitAll())
.logout(logout -> logout.logoutUrl("/logout"))
.csrf(AbstractHttpConfigurer::disable);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
显示登录表单,但当我尝试登录时,在登录页面中出现以下错误:找不到org.springframework.security.authentication.UsernamePasswordAuthenticationToken的验证提供者。奇怪的是,应用程序日志中没有任何内容被打印出来。
我还尝试提供一个AuthenticationManager
,将第一个bean替换为
@Bean
public AuthenticationManager authenticationManager(AuthenticationManagerBuilder authBuilder,
PasswordEncoder passwordEncoder) throws Exception {
UserDetails user = User.builder()
.username("govbr.20821922459")
.password(passwordEncoder.encode("a"))
.authorities(toAuthorities(List.of("LU_NVL_CONTA_BASICA")))
.build();
return authBuilder.inMemoryAuthentication().withUser(user).and().build();
}
但随后应用程序无法启动,并显示无法将org.springframework.security.config.annotation.authentication.configuration.authenticationConfiguration$EnableGlobalauthenticationAutowiredConfigurer@313c3cb应用于已生成的对象。
有人知道转换旧WebSecurityConfigurerAdapter
的正确方法吗?
Edit:即使将日志级别增加到DEBUG,我在登录尝试中得到的只是
2022-07-27 14:22:26.012 [ ] DEBUG o.s.security.web.FilterChainProxy - Securing POST /login
2022-07-27 14:22:26.013 [ ] DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - Set SecurityContextHolder to empty SecurityContext
2022-07-27 14:22:26.015 [ ] DEBUG o.s.security.web.DefaultRedirectStrategy - Redirecting to /svr/rest/login?error
2022-07-27 14:22:26.015 [ ] DEBUG .s.s.w.c.HttpSessionSecurityContextRepository - Did not store empty SecurityContext
2022-07-27 14:22:26.015 [ ] DEBUG .s.s.w.c.HttpSessionSecurityContextRepository - Did not store empty SecurityContext
2022-07-27 14:22:26.015 [ ] DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - Cleared SecurityContextHolder to complete request
2022-07-27 14:22:26.041 [ ] DEBUG o.s.security.web.FilterChainProxy - Securing GET /login?error
2022-07-27 14:22:26.041 [ ] DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - Set SecurityContextHolder to empty SecurityContext
2022-07-27 14:22:26.042 [ ] DEBUG .s.s.w.c.HttpSessionSecurityContextRepository - Did not store empty SecurityContext
2022-07-27 14:22:26.042 [ ] DEBUG .s.s.w.c.HttpSessionSecurityContextRepository - Did not store empty SecurityContext
2022-07-27 14:22:26.042 [ ] DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - Cleared SecurityContextHolder to complete request
并且对/login
的POST的响应是302重定向到/login?error
,而不引用任何特定的错误消息或代码(除非错误消息是从会话中确定的)。
2条答案
按热度按时间wz1wpwve1#
我发现了问题:这样ApplicationContext中就有两个bean,这必须禁用Spring自动配置代码,该代码创建内存中身份验证工作所必需的任何东西。
解决方案是在选择本地概要文件时禁用生产bean,这似乎是唯一可能的解决方案:添加
@Primary
和添加优先级高于生产bean的@Order
都不起作用。Edit:实际上,配置是由
InitializeUserDetailsBeanManagerConfigurer
类完成的,它检查是否只有一个类型为UserDetailsService
的bean(它甚至在其Javadoc中进行了说明)。另一种可能是手动创建一个
AuthenticationProvider
,指向InMemoryUserDetailsManager
。为此,只需注册一个GlobalAuthenticationConfigurerAdapter
bean(这是在构建AuthenticationManager
时配置AuthenticationManager
的一种通用方法):vatpfxk52#
在非WebSecurityConfigurerAdapter配置中,我在获取身份验证管理器的句柄时遇到了问题,除非我在dsl中使用apply()。但我认为您可以在没有身份验证管理器的情况下使用此方法。警告:这个例子没有使用在任何生产环境中都应该使用的密码编码器。