如何使用Spring在auth-redirect响应上添加头



对于Spring Boot与htmx的集成,如果htmx完成了传入请求,并且用户不再登录,我需要一种添加标头的方法。

在正常流程中,用户被重定向到登录页面。然而,当有一个由htmx完成的请求时,这是一个AJAX请求,并且重定向不会发生。

建议的解决方案是,如果请求上有HX-Request标头,则服务器应在响应上放置HX-Refresh: true标头。这将使htmx进行一次完整的页面刷新。

我的安全配置如下:

@Configuration
public class WebSecurityConfiguration {
private final ClientRegistrationRepository clientRegistrationRepository;
public WebSecurityConfiguration(ClientRegistrationRepository clientRegistrationRepository) {
this.clientRegistrationRepository = clientRegistrationRepository;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests(registry -> {
registry.mvcMatchers("/actuator/info", "/actuator/health").permitAll();
registry.mvcMatchers("/**").hasAuthority(Roles.ADMIN);
registry.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll();
registry.anyRequest().authenticated();
});
http.oauth2Client();
http.oauth2Login();
http.logout(logout -> logout.logoutSuccessHandler(oidcLogoutSuccessHandler()));
return http.build();
}
private LogoutSuccessHandler oidcLogoutSuccessHandler() {
OidcClientInitiatedLogoutSuccessHandler logoutSuccessHandler = new OidcClientInitiatedLogoutSuccessHandler(clientRegistrationRepository);
// Sets the location that the End-User's User Agent will be redirected to
// after the logout has been performed at the Provider
logoutSuccessHandler.setPostLogoutRedirectUri("{baseUrl}");
return logoutSuccessHandler;
}
}

我尝试了一个过滤器:

public Filter htmxFilter() {
return new Filter() {
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
filterChain.doFilter(servletRequest, servletResponse);
String htmxRequestHeader = request.getHeader("HX-Request");
System.out.println("htmxRequestHeader = " + htmxRequestHeader);
System.out.println(response.getStatus());
if (htmxRequestHeader != null
&& response.getStatus() == 302) {
System.out.println("XXXXXXXXXXX");
response.setHeader("HX-Refresh", "true");
}
}
};
}

但是response.getStatus()从来都不是302(尽管我可以在Chrome中看到302响应状态(。

我也尝试过拦截:

@Bean
public HandlerInterceptor htmxHandlerInterceptor() {
return new HandlerInterceptor() {
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
boolean htmxRequest = request.getHeader("HX-Request") != null;
String htmxRequestHeader = request.getHeader("HX-Request");
System.out.println("htmxRequestHeader = " + htmxRequestHeader);
System.out.println(response.getStatus());
if( htmxRequest && response.getStatus() == 302) {
response.setHeader("HX-Refresh", "true");
}
}
};
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeInterceptor());
registry.addInterceptor(htmxHandlerInterceptor());//.order(Ordered.HIGHEST_PRECEDENCE);
}

这也不起作用,没有302响应状态。

我也试过使用注释掉的order(Ordered.HIGHEST_PRECEDENCE),但并没有任何区别。

还有其他选择吗?

当请求到达受保护的端点且未通过身份验证时,Spring Security会执行其AuthenticationEntryPoint接口以启动身份验证方案。

您可以创建自己的AuthenticationEntryPoint,将头和委托添加到LoginUrlAuthenticationEntryPoint(或您正在使用的其他实现(。

@Bean
SecurityFilterChain appSecurity(HttpSecurity http) throws Exception {
http
//...
.exceptionHandling(exception -> exception
.authenticationEntryPoint(new HxRefreshHeaderAuthenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")))
);
return http.build();
}
public class HxRefreshHeaderAuthenticationEntryPoint implements AuthenticationEntryPoint {
private final AuthenticationEntryPoint delegate;
public HxRefreshHeaderAuthenticationEntryPoint(AuthenticationEntryPoint delegate) {
this.delegate = delegate;
}
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {

// Add the header
this.delegate.commence(request, response, authException);
}
}

您需要确保您的过滤器在任何Spring Security过滤器之前运行。请参阅SecurityProperties.DEFAULT_FILTER_ORDER或HttpSecurity#addFilterBefore

最新更新