一聚教程网:一个值得你收藏的教程网站

热门教程

spring security 3.1中login和logout后的跳转处理

时间:2022-06-29 00:43:11 编辑:袖梨 来源:一聚教程网

spring security的form-login提供了default-target-url作为登录成功后的跳转地址,唯独没有允许传递一个redirectUrl参数来作为成功后的跳转地址。
同样的logout标签提供了logout-success-url作为退出成功后的跳转地址,也没有提供允许传递redirectUrl参数来进行跳转。
本来打算自己实现和AdminAuthSuccessHandler和LogoutSuccessHandler来接收redirectUrl参数进行跳转的,结果查看spring security的代码无意间发现spring security居然提供了targetUrlParameter作为跳转地址的参数,只是Security Namespace没有相关的标签或属性。于是在读完跳转相关的代码之后自己写了以下配置。
注:如果直接允许传递redirectUrl作为跳转地址,会有一定的安全风险。在使用之前,确保redirectUrl可信。下面的这段配置有一定安全隐患。

代码如下 复制代码























通过查看源码我们发现,SimpleUrlLogoutSuccessHandler继续了AbstractAuthenticationTargetUrlRequestHandler,同样的SavedRequestAwareAuthenticationSuccessHandler也是继承了AbstractAuthenticationTargetUrlRequestHandler,而在AbstractAuthenticationTargetUrlRequestHandler的handle方法里,我们发现它是通过determineTargetUrl()方法来决定Redirect地址的。

代码如下 复制代码
public class SimpleUrlLogoutSuccessHandler extends AbstractAuthenticationTargetUrlRequestHandler
implements LogoutSuccessHandler {

public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
super.handle(request, response, authentication);
}

}

通过分析determineTargetUrl我们得出以下结论:
①如果alwaysUseDefaultTargetUrl为true,则跳转地址始终为defaultTargetUrl
②如果targetUrlParameter不为null,则从request中targetUrlParameter指定的参数名获取跳转地址
③如果useReferer为true,并且前两步没有获取到跳转地址,则从请求头中的Referer获取跳转地址
④如果以上几步都为空,则使用设置的defaultTargetUrl作为跳转地址
⑤defaultTargetUrl的默认值是"/"

在最终跳转时,spring security使用一个RedirectStrategy策略来进行跳转,一般都是使用DefaultRedirectStrategy来进行跳转,你也可以实现自己的RedirectStrategy并配置在adminAuthSuccessHandler的bean定义中。

在刚开始的时候我们说过“如果直接允许传递redirectUrl作为跳转地址,会有一定的安全风险”。如果别人通过你的login或logout传递redirectUrl参数误导用户跳到了病毒木马网站,那这肯定是你的安全做的不够,为了安全我们,我们需要实现自己的SafeRedirectStrategy,如下所示,在跳转之前对URL进行了白名单校验。

代码如下 复制代码
/**
* 安全的RedirectStrategy,主要是判断跳转地址是否在白名单中
* @author guoweiwei [email protected]
*
*/
public class SafeRedirectStrategy implements RedirectStrategy {

protected final Log logger = LogFactory.getLog(getClass());

private boolean contextRelative;

/**
* Redirects the response to the supplied URL.
*


* If contextRelative is set, the redirect value will be the value after the request context path. Note
* that this will result in the loss of protocol information (HTTP or HTTPS), so will cause problems if a
* redirect is being performed to change to HTTPS, for example.
*/
public void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url) throws IOException {
String redirectUrl = calculateRedirectUrl(request.getContextPath(), url);


try {
if(UrlUtils.isAbsoluteUrl(redirectUrl)){
redirectUrl = UrlUtil.buildRedirectLink(redirectUrl, false);
}
} catch (Exception e) {
throw new IOException("error redirect url", e);
}


redirectUrl = response.encodeRedirectURL(redirectUrl);

if (logger.isDebugEnabled()) {
logger.debug("Redirecting to '" + redirectUrl + "'");
}

response.sendRedirect(redirectUrl);
}

private String calculateRedirectUrl(String contextPath, String url) {
if (!UrlUtils.isAbsoluteUrl(url)) {
if (contextRelative) {
return url;
} else {
return contextPath + url;
}
}

// Full URL, including http(s)://

if (!contextRelative) {
return url;
}

// Calculate the relative URL from the fully qualified URL, minus the scheme and base context.
url = url.substring(url.indexOf("://") + 3); // strip off scheme
url = url.substring(url.indexOf(contextPath) + contextPath.length());

if (url.length() > 1 && url.charAt(0) == '/') {
url = url.substring(1);
}

return url;
}

/**
* If true, causes any redirection URLs to be calculated minus the protocol
* and context path (defaults to false).
*/
public void setContextRelative(boolean useRelativeContext) {
this.contextRelative = useRelativeContext;
}

}

上面代码中UrlUtil为自己实现的一个Url处理工具,buildRedirectLink会对url做白名单校验。完了别忘了在servlet.xml的bean配置中加入safeRedirectStrategy。如下所示:

代码如下 复制代码













热门栏目