securityFilterChain SpringBoot 3 中的authenticationManager 问题

问题描述 投票:0回答:2

正如你在这张照片中看到的,我试图在我的 .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 而造成的障碍,我相信有人可以帮助我找到解决方案。

java spring spring-boot authentication security
2个回答
0
投票

由于从 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 是需要身份验证管理器的过滤器,我向它传递一个虚拟实现,一旦完成安全配置,我就可以“热交换”真正的实现。

我希望您已经解决了您的问题。如果没有,我希望这对您有所帮助!


-1
投票

请查看我最近的 Spring Boot 3 项目: https://github.com/thevarga04/ucimsa/blob/main/src/main/java/ucimsa/config/WebSecurityConfig.java

在这篇文章中,我详细阐述了几个主题: 注册后自动登录Spring Boot 3/Spring security 6

© www.soinside.com 2019 - 2024. All rights reserved.