成功身份验证后的Spring安全重定向



我正在尝试向一组api端点添加访问控制,遇到的问题是,无论原始请求是/api/apple还是/api/orange,服务都重定向到/。我目前设置了一个过滤器来读取自定义http标头以进行身份验证,我使用的过滤器是从AbstractAuthenticationProcessingFilter扩展而来的。文档中说,AbstractAuthenticationProcessingFilter在成功身份验证后重定向到特定的url,但这不是我想要的api行为。我想我可能使用了错误的过滤器,但我不知道我应该使用哪一个。我能得到一些关于我可能做错了什么和应该做什么的帮助吗?

过滤链配置:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
AuthenticationManager customAuthenticationManager(PreAuthProvider preAuthProvider) {
return new ProviderManager(List.of(preAuthProvider));
}
@Bean
SessionAuthFilter customAuthFilter(AuthenticationManager authManager, CustomUserDetails userDetails) {
return new SessionAuthFilter(
new OrRequestMatcher(
new AntPathRequestMatcher("/apple/**"),
new AntPathRequestMatcher("/orange/**")
),
authManager,
userDetails);
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http, SessionAuthFilter authFilter) throws Exception {
http.exceptionHandling()
.authenticationEntryPoint(new Http403ForbiddenEntryPoint())
.accessDeniedHandler(new AccessDeniedHandlerImpl())
.and()
.formLogin().disable()
.httpBasic().disable()
.authorizeRequests()
.antMatchers(
"/",
"/error",
"/v3/api-docs/**",
"/swagger-ui/**",
"/swagger-ui.html",
"/actuator/**"
).permitAll()
.antMatchers(GET, "/apple").hasAuthority("getApples")
.antMatchers(GET, "/orange").hasAuthority("getOranges")
.anyRequest().authenticated()
.and()
.addFilterBefore(authFilter, AbstractPreAuthenticatedProcessingFilter.class)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
return http.build();
}

过滤器实现:

public class SessionAuthFilter extends AbstractAuthenticationProcessingFilter {
private final CustomUserDetails userDetails;
protected SessionAuthFilter(RequestMatcher requestMatcher, AuthenticationManager authenticationManager,
CustomUserDetails userDetails) {
super(requestMatcher, authenticationManager);
this.userDetails = userDetails;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
var sessionToken = request.getHeader("SessionToken") != null ? request.getHeader("SessionToken").trim() : null;
var user = userDetails.loadUserByUsername(sessionToken);
var authentication = new PreAuthenticatedAuthenticationToken(user.getUsername(), user.getPassword(),
user.getAuthorities());
authentication.setAuthenticated(user.isCredentialsNonExpired());
authentication.setDetails(userDetails);
SecurityContextHolder.getContext().setAuthentication(authentication);
return this.getAuthenticationManager().authenticate(authentication);
}
}

身份验证提供商:

@Component
@Slf4j
public class PreAuthProvider implements AuthenticationProvider {
private boolean throwExceptionWhenTokenRejected;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (!this.supports(authentication.getClass())) {
return null;
}  else {
log.debug(String.valueOf(LogMessage.format("PreAuthenticated authentication request: %s", authentication)));
if (authentication.getPrincipal() == null) {
log.debug("No pre-authenticated principal found in request.");
if (this.throwExceptionWhenTokenRejected) {
throw new BadCredentialsException("No pre-authenticated principal found in request.");
} else {
return null;
}
} else if (authentication.getCredentials() == null) {
log.debug("No pre-authenticated credentials found in request.");
if (this.throwExceptionWhenTokenRejected) {
throw new BadCredentialsException("No pre-authenticated credentials found in request.");
} else {
return null;
}
} else if (!authentication.isAuthenticated()) {
throw new InsufficientAuthenticationException("Session token likely no longer valid.");
}
return authentication;
}
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(PreAuthenticatedAuthenticationToken.class);
}
public void setThrowExceptionWhenTokenRejected(boolean throwExceptionWhenTokenRejected) {
this.throwExceptionWhenTokenRejected = throwExceptionWhenTokenRejected;
}
}

如果在AbstractAuthenticationProcessingFilter实现中将continueChainBeforeSuccessfulAuthentication设置为true,则可以延迟重定向使用您自己的成功处理程序实现将完全停止重定向行为我只需要修改过滤器构造函数,结果是:

protected SessionAuthFilter(RequestMatcher requestMatcher, AuthenticationManager authenticationManager,
CustomUserDetails userDetails) {
super(requestMatcher, authenticationManager);
this.userDetails = userDetails;
this.setContinueChainBeforeSuccessfulAuthentication(true);
this.setAuthenticationSuccessHandler((request, response, authentication) -> {});
}

另一种方法是实现不同的Filter,如OncePerRequestFilter或GenericFilterBean,以自己处理身份验证。

最新更新