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

热门教程

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 gww0426@163.com
 *
 */
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。如下所示:

 代码如下 复制代码

   
   
   
 

  
 
     
     
     
 

  
 

 

热门栏目