gpt4 book ai didi

ajax - Spring - 在 Ajax 请求失败后成功登录后重定向到链接

转载 作者:行者123 更新时间:2023-12-01 04:29:55 28 4
gpt4 key购买 nike

我有一个网站,需要根据用户操作在元素内异步呈现一些 HTML。如果用户的 session 过期,事情会变得棘手,但可以通过创建自定义 AuthenticationEntryPoint 来解决。类如 this SO questionthis SO question建议。

一旦用户重新登录,我的问题就出现了,因为用户被重定向到最后一个请求的 URL,这恰好是 Ajax 请求,因此我的用户被重定向到 HTML 的片段,而不是它浏览的最后一个页面。

我能够通过删除自定义 AuthenticationEntryPoint 上的 session 属性来解决此问题。 :

if (ajaxOrAsync) {
request.getSession().removeAttribute("SPRING_SECURITY_SAVED_REQUEST");
}

我的问题来了。

虽然前面的代码解决了我的问题,但它具有将用户重定向到主页而不是它浏览的最后一页的副作用(因为没有保存的请求)。这不是什么大问题,但它会使网站不一致,因为如果最后一个请求是异步请求,它会被重定向到主页,但如果是正常请求,它会被重定向到最后浏览的页面。 =(

我设法编码它来处理这种情况:
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.PortResolver;
import org.springframework.security.web.PortResolverImpl;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.savedrequest.DefaultSavedRequest;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import static org.apache.commons.lang.StringUtils.isBlank;

public class CustomAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {
... // Some not so relevant code

@Override
public void commence(final HttpServletRequest request,
final HttpServletResponse response,
final AuthenticationException authException) throws IOException, ServletException {
... // some code to determine if the request is an ajax request or an async one
if (ajaxOrAsync) {
useRefererAsSavedRequest(request);

response.sendError(SC_UNAUTHORIZED);
} else {
super.commence(request, response, authException);
}
}

private void useRefererAsSavedRequest(final HttpServletRequest request) {
request.getSession().removeAttribute(SAVED_REQUEST_SESSION_ATTRIBUTE);

final URL refererUrl = getRefererUrl(request);
if (refererUrl != null) {
final HttpServletRequestWrapper newRequest = new CustomHttpServletRequest(request, refererUrl);
final PortResolver portResolver = new PortResolverImpl();
final DefaultSavedRequest newSpringSecuritySavedRequest = new DefaultSavedRequest(newRequest, portResolver);

request.getSession().setAttribute(SAVED_REQUEST_SESSION_ATTRIBUTE, newSpringSecuritySavedRequest);
}
}

private URL getRefererUrl(final HttpServletRequest request) {
final String referer = request.getHeader("referer");

if (isBlank(referer)) {
return null;
}

try {
return new URL(referer);
} catch (final MalformedURLException exception) {
return null;
}
}

private class CustomHttpServletRequest extends HttpServletRequestWrapper {
private URL url;

public CustomHttpServletRequest(final HttpServletRequest request, final URL url) {
super(request);
this.url = url;
}

@Override
public String getRequestURI() {
return url.getPath();
}

@Override
public StringBuffer getRequestURL() {
return new StringBuffer(url.toString());
}

@Override
public String getServletPath() {
return url.getPath();
}

}
}

前面的代码解决了我的问题,但它是解决我的重定向问题的一种非常hacky 的方法(我克隆并覆盖了原始请求... +不寒而栗+)。

所以我的问题是, 有没有其他方法可以重写 Spring 在成功登录后用来重定向用户的链接(考虑到我正在使用的条件)?

我看过 Spring 的 AuthenticationSuccessHandler ,但我还没有找到一种在 Ajax 请求失败的情况下将引用 URL 传递给它的方法。

最佳答案

由于在 reading the docs 时出现的一个想法,我找到了解决问题的可接受的解决方案。稍后浏览此其他 SO answer .简而言之,我必须创建自己的自定义 ExceptionTranslationFilter ,并覆盖 sendStartAuthentication不保存请求缓存。

如果看一看ExceptionTranslationFilter代码,它看起来像这样(对于 Finchley SR1):

protected void sendStartAuthentication(HttpServletRequest request,
HttpServletResponse response, FilterChain chain,
AuthenticationException reason) throws ServletException, IOException {
SecurityContextHolder.getContext().setAuthentication(null);
requestCache.saveRequest(request, response); // <--- Look at me
logger.debug("Calling Authentication entry point.");
authenticationEntryPoint.commence(request, response, reason);
}

所以,为了不保存来自 Ajax 请求的数据,我应该实现一个 CustomExceptionTranslationFilter它的作用是这样的:
@Override
protected void sendStartAuthentication(final HttpServletRequest request,
final HttpServletResponse response,
final FilterChain chain,
final AuthenticationException authenticationException) throws ServletException, IOException {
... // some code to determine if the request is an ajax request or an async one
if (isAjaxOrAsyncRequest) {
SecurityContextHolder.getContext().setAuthentication(null);

authenticationEntryPoint.commence(request, response, authenticationException);
} else {
super.sendStartAuthentication(request, response, chain, authenticationException);
}
}

这使得 CustomAuthenticationEntryPoint逻辑更简单:
@Override
public void commence(final HttpServletRequest request,
final HttpServletResponse response,
final AuthenticationException authException) throws IOException, ServletException {
... // some code to determine if the request is an ajax request or an async one, again
if (isAjaxOrAsyncRequest) {
response.sendError(SC_UNAUTHORIZED);
} else {
super.commence(request, response, authException);
}
}

还有我的 CustomWebSecurityConfigurerAdapter应该这样配置:
@Override
protected void configure(final HttpSecurity http) throws Exception {
final CustomAuthenticationEntryPoint customAuthenticationEntryPoint =
new CustomAuthenticationEntryPoint("/login-path");

final CustomExceptionTranslationFilter customExceptionTranslationFilter =
new CustomExceptionTranslationFilter(customAuthenticationEntryPoint);

http.addFilterAfter(customExceptionTranslationFilter, ExceptionTranslationFilter.class)
....
.permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.exceptionHandling()
.authenticationEntryPoint(customAuthenticationEntryPoint)
....;
}

关于ajax - Spring - 在 Ajax 请求失败后成功登录后重定向到链接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53016819/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com