如何让 Spring 自定义身份验证提供程序工作

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

我正在使用 spring-security 6 来实现自定义身份验证。实际的身份验证基于标头中发送的签名。因此,我尝试实现一个示例以使结构正常工作。下面是我的代码。

提供商身份验证:

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

@Override
public Authentication authenticate(final Authentication authentication) throws AuthenticationException {
    final String name = authentication.getName();
    final String password = authentication.getCredentials().toString();
    if (!"admin".equals(name) || !"system".equals(password)) {
        return null;
    }
    return authenticateAgainstThirdPartyAndGetAuthentication(name, password);
}

@Override
public boolean supports(Class<?> authentication) {
    return true;
}

private static UsernamePasswordAuthenticationToken authenticateAgainstThirdPartyAndGetAuthentication(String name, String password) {
    final List<GrantedAuthority> grantedAuths = new ArrayList<>();
    final UserDetails principal = new User(name, password, grantedAuths);
    return new UsernamePasswordAuthenticationToken(principal, password, grantedAuths);
  }
}

菲勒:

@Component
public class EverybodyAuthenticationFilter extends OncePerRequestFilter {
    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        SecurityContextHolder.createEmptyContext();
        // THIS IS ONLY FOR TESTS. TO GET THIS WORK SENDING HARD CODED TOKEN. THIS SHOULD BE
        // CREATED FROM HEADER VALUES.
        customAuthenticationProvider.authenticate(new UsernamePasswordAuthenticationToken("admin",
                "system"));
        filterChain.doFilter(request, response);
    }
}

安全配置:

@EnableWebSecurity
@Configuration
@ComponentScan("com.example.demo")
public class SecurityConfig{

    @Autowired
    private CustomAuthenticationProvider authProvider;

    @Bean
    public AuthenticationManager authManager(HttpSecurity http) throws Exception {
        AuthenticationManagerBuilder authenticationManagerBuilder =
                http.getSharedObject(AuthenticationManagerBuilder.class);
        authenticationManagerBuilder.authenticationProvider(authProvider);
        return authenticationManagerBuilder.build();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http,
                                           AuthenticationManager authenticationManager,
                                           EverybodyAuthenticationFilter every) throws Exception {
        return http.authorizeHttpRequests(expressionInterceptUrlRegistry ->
                        expressionInterceptUrlRegistry.anyRequest().authenticated())
            .addFilterBefore(every, BasicAuthenticationFilter.class)
                .authenticationManager(authenticationManager)
            .build();
    }
}

控制器:

@Controller
public class HomeController {
    private static final String HOME_VIEW = "home/index";

    @GetMapping("/home")
    public String home(HttpServletRequest request){
        return HOME_VIEW;
    }
}

在此代码中

EverybodyAuthenticationFilter
发送硬编码令牌仅用于测试。因此我的理解是这应该适用于所有请求。但是我收到 403 错误。我遇到了以下讨论,其中说 spring-security 6 客户身份验证提供程序的工作方式不同。

https://github.com/spring-projects/spring-security/issues/12602

我怎样才能让它发挥作用?

java spring spring-security spring-boot-3
1个回答
0
投票

让我们与 Spring Security 进行更多集成,而不是扩展

OncePerRequestFilter
并让过滤器使用
AbstractAuthenticationProcessingFilter
AuthenticationManager

是的,这个类没有注释。

接下来,使用 Spring security 将其注册到过滤器链中,创建一个自定义 DSL 并将其应用于常规配置。

public class EverybodyAuthenticationFilter extends AbstractAuthenticationProcessingFilter { public EverybodyAuthenticationFilter(AuthenticationManager authenticationManager) { super("/**", authenticationManager); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken("admin", "system")); } }

这将执行 2 件事,它将重新使用共享的预配置 
public class CustomSecurityConfigurer extends AbstractHttpConfigurer<CustomSecurityConfigurer, HttpSecurity> { @Override public void configure(HttpSecurity http) throws Exception { AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class); http.addFilterBefore(new EverybodyAuthenticationFilter(authenticationManager), BasicAuthenticationFilter.class); } public static CustomSecurityConfigurer customSecurityConfigurer() { return new CustomSecurityConfigurer(); } }

,其中将包括您的自定义

AuthenticationManager
并仅将其注册到安全过滤器链中。后者由于这不再是 Spring 管理的 bean。
最后将此 DSL 应用于常规配置。
AuthenticationProvider

这样您就可以更好地与 Spring Security 集成

并且
您的
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.apply(CustomSecurityConfigurer.customSecurityConfigurer()); return http.authorizeHttpRequests( auth -> auth.anyRequest().authenticated()) .build(); } }

将被咨询。发出请求时,您可以在日志中看到您的过滤器和提供程序正在使用。 CustomAuthenticationProvider

    

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