正如你在这张照片中看到的,我试图在我的 .addFilter(new JwtUsernameAndPasswordAuthenticationFilter()) 中添加一个authenticationManager,但 springboot 不允许,因为我使用 securityFilterChain 方法。
################################################## ##############################################
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class ApplicationSecurityConfig {
private final PasswordEncoder passwordEncoder;
private final ApplicationUserService applicationUserService;
@Autowired
public ApplicationSecurityConfig(PasswordEncoder passwordEncoder,
ApplicationUserService applicationUserService) {
this.passwordEncoder=passwordEncoder;
this.applicationUserService = applicationUserService;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilter(new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager()))
.authorizeRequests()
.requestMatchers("/", "/index", "/css/*", "/js/*").permitAll()
.requestMatchers("/api/**").hasRole(ApplicationUserRole.STUDENT.name())
.anyRequest()
.authenticated()
.and()
.build();
}
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(daoAuthenticationProvider());
}
@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder);
provider.setUserDetailsService(applicationUserService);
return provider;
}
}
################################################## #############################################
我的类 JwtUsernameAndPasswordAuthenticationFilter 是这个,
public class JwtUsernameAndPasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final AuthenticationManager authenticationManager;
public JwtUsernameAndPasswordAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
try {
UsernameAndPasswordAuthenticationRequest authenticationRequest = new ObjectMapper()
.readValue(request.getInputStream(), UsernameAndPasswordAuthenticationRequest.class);
Authentication authentication = new UsernamePasswordAuthenticationToken(
authenticationRequest.getUsername(),
authenticationRequest.getPassword()
);
Authentication authenticate = authenticationManager.authenticate(authentication);
return authenticate;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain,
Authentication authResult) throws IOException, ServletException {
String key = "securesecuresecuresecuresecuresecuresecuresecuresecuresecure";
String token = Jwts.builder()
.setSubject(authResult.getName())
.claim("authorities",authResult.getAuthorities())
.setIssuedAt(new Date())
.setExpiration(java.sql.Date.valueOf(LocalDate.now().plusWeeks(2)))
.signWith(Keys.hmacShaKeyFor(key.getBytes()))
.compact();
response.addHeader("Authorization","bearer " + token);
}
}
有人可以帮助我吗?我应该怎么做才能使其在新版本的 springboot 中工作?
无论如何谢谢。
我正在尝试克服由于不同版本的 springboot 而造成的障碍,我相信有人可以帮助我找到解决方案。
由于从 2.7 迁移到版本 3.1.3,我也遇到了类似的问题
早在2.7及之前,当我们扩展WebSecurityConfigurerAdapter时,有“authenticationManagerBean”方法 我确实检查了实现情况,似乎他们还必须进行一些肮脏的修复才能使其正常工作。
基本上所做的就是创建一个小型代理/中介/容器(或任何我们想要调用的名称)类,它将充当占位符,直到身份验证管理器准备就绪。
public class AuthenticationManagerDelegate implements AuthenticationManager {
private AuthenticationManager delegate;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (this.delegate == null) {
throw new RuntimeException("Authentication Manager Delegate is empty!");
}
return this.delegate.authenticate(authentication);
}
void setDelegate(AuthenticationManager delegate) {
this.delegate = delegate;
}
}
那么您的安全配置将如下所示:
@Bean
public SecurityFilterChain configureSecurity(HttpSecurity http,
BCryptPasswordEncoder passwordEncoder) throws Exception {
http
.userDetailsService(this.userService)
.httpBasic(basic -> {
final var filter = new BasicAuthenticationEntryPoint();
filter.setRealmName("THE_SHADOW_REALM");
basic.authenticationEntryPoint(filter);
})
final var authManagerDelegate = new AuthenticationManagerDelegate();
final TokenBasicAuthenticationFilter basicAuthenticationFilter = new TokenBasicAuthenticationFilter(
authManagerDelegate,
this.authTokenService,
this.authTokenHeaderName
);
http.addFilter(basicAuthenticationFilter);
final AuthenticationManager authenticationManager = http
.getSharedObject(AuthenticationManagerBuilder.class)
.userDetailsService(this.userService)
.passwordEncoder(passwordEncoder)
.and()
.build();
authManagerDelegate.setDelegate(authenticationManager);
return http.getOrBuild();
}
在此示例中,TokenBasicAuthenticationFilter 是需要身份验证管理器的过滤器,我向它传递一个虚拟实现,一旦完成安全配置,我就可以“热交换”真正的实现。
我希望您已经解决了您的问题。如果没有,我希望这对您有所帮助!
请查看我最近的 Spring Boot 3 项目: https://github.com/thevarga04/ucimsa/blob/main/src/main/java/ucimsa/config/WebSecurityConfig.java
在这篇文章中,我详细阐述了几个主题: 注册后自动登录Spring Boot 3/Spring security 6