spring 将AuthenticationManager传递给自定义筛选器

cunj1qz1  于 2023-04-28  发布在  Spring
关注(0)|答案(3)|浏览(168)

由于Spring Security更新了,我不得不在代码中做一些更改。这是我现在的配置类。

public class SecurityConfig {

    private final UserDetailsServiceImpl userDetailsService;
    private final UserRepository userRepository;

    public SecurityConfig(UserDetailsServiceImpl userDetailsService, UserRepository userRepository) {
        this.userDetailsService = userDetailsService;
        this.userRepository = userRepository;
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .addFilter(new CustomAuthenticationFilter(authenticationManager()))
                .addFilter(new CustomAuthorizationFilter(authenticationManager(), userRepository))
                .authorizeRequests()
                .antMatchers(HttpMethod.POST, "/user/users/save").permitAll()
                .antMatchers(HttpMethod.POST, "/login").permitAll()
                .antMatchers(HttpMethod.POST, "/users//register").permitAll()
                .antMatchers("/**").permitAll() // Only for testing purposes
                .antMatchers("/user/**").hasAuthority("ADMIN")
                .antMatchers("/user/**").authenticated();
        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

但是,由于我已经将configure方法和身份验证管理器更改为bean,所以我无法将身份验证管理器传递给我的过滤器。看起来像这样。

public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private final AuthenticationManager authenticationManager;
    @Value("${security.key}")
    private String secretKey;

    public CustomAuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        LoginRequest loginRequest = null;
        try {
            loginRequest = new ObjectMapper().readValue(request.getInputStream(), LoginRequest.class);
        } catch (IOException e) {
            throw new IllegalArgumentException();
        }
        String username = loginRequest.getUsername();
        String password = loginRequest.getPassword();
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
        return authenticationManager.authenticate(authenticationToken);
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException {
        UserDetailsImpl user = (UserDetailsImpl) authentication.getPrincipal();
        Algorithm algorithm = HMAC512(secretKey.getBytes());
        List<String> list = user.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
        String accessToken = JWT.create()
                .withSubject(user.getUsername())
                .withExpiresAt(new Date(System.currentTimeMillis()+10*60*1000))
                .withClaim("authorities", list)
                .sign(algorithm);
        response.addHeader("authorization","Bearer " + accessToken);
    }

}

如何将authenticationManager注入到过滤器中?

wljmcqd8

wljmcqd81#

访问AuthenticationManager的推荐方法是使用自定义DSL。这实际上是Spring Security内部实现HttpSecurity.authorizeRequests()等方法的方式。

public class MyCustomDsl extends AbstractHttpConfigurer<MyCustomDsl, HttpSecurity> {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
        http.addFilter(new CustomAuthenticationFilter(authenticationManager));
    }

    public static MyCustomDsl customDsl() {
        return new MyCustomDsl();
    }
}

然后,在构建SecurityFilterChain时可以应用自定义DSL:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    // ...
    http.apply(customDsl());
    return http.build();
}

这在关于从WebSecurityConfigurerAdapter迁移的博客文章“访问本地AuthenticationManager”一节中进行了描述。

vojdkbi0

vojdkbi02#

我遇到了同样的问题,解决了:

public class SecurityConfig {

   @Autowired
   private AuthenticationConfiguration authenticationConfiguration;

   @Bean
   protected SecurityFilterChain configure(HttpSecurity http) throws Exception {
      http.addFilterBefore(new AuthenticationFilter(authenticationConfiguration.getAuthenticationManager()), BasicAuthenticationFilter.class)
   }

}
qcbq4gxm

qcbq4gxm3#

我猜这应该可以工作(因为所有对@Bean方法的调用都是通过CGLIB代理的,因此返回bean的缓存版本):

public class SecurityConfig {

    private final UserDetailsServiceImpl userDetailsService;
    private final UserRepository userRepository;
    private final AuthenticationConfiguration authenticationConfiguration;

    public SecurityConfig(UserDetailsServiceImpl userDetailsService, UserRepository userRepository, AuthenticationConfiguration authenticationConfiguration) {
        this.userDetailsService = userDetailsService;
        this.userRepository = userRepository;
        this.authenticationConfiguration = authenticationConfiguration;
    }

    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .addFilter(new CustomAuthenticationFilter(authenticationManager()))
                .addFilter(new CustomAuthorizationFilter(authenticationManager(), userRepository))
                .authorizeRequests()
                .antMatchers(HttpMethod.POST, "/user/users/save").permitAll()
                .antMatchers(HttpMethod.POST, "/login").permitAll()
                .antMatchers(HttpMethod.POST, "/users//register").permitAll()
                .antMatchers("/**").permitAll() // Only for testing purposes
                .antMatchers("/user/**").hasAuthority("ADMIN")
                .antMatchers("/user/**").authenticated();
        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

如果存在循环依赖问题,您可以在构造函数中的AuthenticationConfiguration authenticationConfiguration上放置@Lazy annotation。

相关问题