我正在使用 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
我怎样才能让它发挥作用?
让我们与 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