重定向策略接口定义
Spring Security Web 使用的页面重定向机制通过重定向策略接口定义:
package org.springframework.security.web;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Encapsulates the redirection logic for all classes in the framework which perform
* redirects.
* 面向框架内执行页面重定向的所有类封装重定向逻辑。
*
* @since 3.0
*/
public interface RedirectStrategy {
/**
* Performs a redirect to the supplied URL 页面重定向到url
* @param request the current request 当前请求
* @param response the response to redirect 需要执行重定向的响应
* @param url the target URL to redirect to, for example "/login"
*/
void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url)
throws IOException;
}
重定向策略缺省实现类
而整个框架内部,缺省使用了以上接口的实现类DefaultRedirectStrategy
来执行相应的页面重定向任务:
package org.springframework.security.web;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.web.util.UrlUtils;
public class DefaultRedirectStrategy implements RedirectStrategy {
protected final Log logger = LogFactory.getLog(getClass());
// true 的话重定向URL要去掉协议部分,contex path部分,缺省为 false
private boolean contextRelative;
/**
* Redirects the response to the supplied URL.
* 重定向页面到指定的url
*
* 如果属性 contextRelative为true,重定向值会是上下文路径`context path`之后的部分。
* 这样的话有可能导致重定向丢失协议信息,也就是HTTP/HTTPS部分,所以举例来讲,
* 如果你正在从HTTP跳转到HTTPS,这样做可能会导致问题。
*/
public void sendRedirect(HttpServletRequest request, HttpServletResponse response,
String url) throws IOException {
// 计算重定向url,主要是结合考虑属性 contextRelative
String redirectUrl = calculateRedirectUrl(request.getContextPath(), url);
// 编码重定向url,如果没有必要编码,会原值返回。
// 这里的编码并不是指一般意义上的encodeURL(),而主要是考虑sessionID是否需要编码
// 进URL。
redirectUrl = response.encodeRedirectURL(redirectUrl);
if (logger.isDebugEnabled()) {
logger.debug("Redirecting to '" + redirectUrl + "'");
}
// 执行重定向
response.sendRedirect(redirectUrl);
}
protected String calculateRedirectUrl(String contextPath, String url) {
if (!UrlUtils.isAbsoluteUrl(url)) {
// 如果 url 不是绝对路径URL,并且 contextRelative, 则直接返回该 url
if (isContextRelative()) {
return url;
}
else {
// 如果 url 不是绝对路径URL,并且 contextRelative为false,
// 则url前面附加上 contextPath 返回
return contextPath + url;
}
}
// Full URL, including http(s)://
// url 是绝对路径url的情况, 也就是包含了 http(s)://协议部分的
// 完整url路径
if (!isContextRelative()) {
// 绝对路径url的情况,如果 contextRelative 为 false, 则直接返回 url
return url;
}
// Calculate the relative URL from the fully qualified URL, minus the last
// occurrence of the scheme and base context.
// 绝对路径url,并且 contextRelative 的情况,
// 此时从url中取出协议部分,contextPath部分,contxtPath后面的/然后返回剩余部分
url = url.substring(url.lastIndexOf("://") + 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;
}
public void setContextRelative(boolean useRelativeContext) {
this.contextRelative = useRelativeContext;
}
protected boolean isContextRelative() {
return contextRelative;
}
}
使用举例
SimpleUrlAuthenticationFailureHandler
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
SimpleUrlAuthenticationSuccessHandler
/SimpleUrlLogoutSuccessHandler
基类AbstractAuthenticationTargetUrlRequestHandler
中:
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
LoginUrlAuthenticationEntryPoint
private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();