Spring Security - 更改 RedirectStrategy 的所有实例
Posted
技术标签:
【中文标题】Spring Security - 更改 RedirectStrategy 的所有实例【英文标题】:Spring Security - Change all instances of RedirectStrategy 【发布时间】:2015-12-11 04:41:12 【问题描述】:我有一个运行多个 WAR 文件的 tomcat 实例。 tomcat 实例在 Apache 服务器后面被代理,因此上下文路径被剥离。相反,我使用的是子域:
基本上,我的设置如下所示:
http://localhost:8080/app1 -> http://app1.example.com/
http://localhost:8080/app2 -> http://app2.example.com/
我需要做的是使所有重定向上下文相对,因为我不再在 URL 中包含上下文路径。我注意到 Spring Security 允许使用默认类 DefaultRedirectStrategy 将重定向设置为“上下文相关”。为了使重定向正常工作,我必须覆盖多个对象,这样我就可以简单地将具有 contextRelative=false 的 DefaultRedirectStrategy 的默认实例换成我自己创建的具有 contextRelative=true 的 DefaultRedirectStrategy 实例。
有没有更简单的方法可以告诉 spring 我想在没有上下文路径的情况下全局重定向所有 URL?我已经尝试在我的配置中注册 DefaultRedirectStrategy 但没有成功。
@Bean
public RedirectStrategy createRedirectStrategy()
// create the redirect strategy to set the urls to context relative
DefaultRedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
redirectStrategy.setContextRelative(true);
return redirectStrategy;
^ 这太容易了。不知道为什么 spring 不允许这个工作。
我是不是找错地方了?
【问题讨论】:
【参考方案1】:事实上,你不能仅仅通过定义一个新的@Bean
来改变DefaultRedirectStrategy
那,我想这太全球化了
您可以改为通过public void setRedirectStrategy(RedirectStrategy redirectStrategy)
将AbstractAuthenticationTargetUrlRequestHandler.redirectStrategy
更改为DefaultRedirectStrategy
的另一个实例。
@Component
public class YourAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler
YourAuthenticationSuccessHandler ()
// To avoid default behavior that prefixes `server.servlet.context-path`
DefaultRedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
redirectStrategy.setContextRelative(true); // <-- same as in the OP question
this.setRedirectStrategy(redirectStrategy); // <-- change redirect strategy
//
【讨论】:
【参考方案2】:我一直在努力解决与您相同的问题。试图覆盖 Spring Security 的 AuthenticationEntryPoint 和 SuccessHandler 以便它们使用没有上下文路径的 url。当它打动我时,我的子域配置基本上是说,每当有人打开http://app1.example.com/ 时,他/她应该被重定向到http://example.com/app1,所以就 Tomcat 和 Spring Security 如何看到 url 而言,上下文确实存在。因此,也许与其在 Spring Security 中进行疯狂的黑客攻击,不如以某种方式摆脱上下文路径本身。
所以我最后做了什么,如下所示。
子域配置
我将我的两个子域重定向到同一个地址,这是我运行我的 tomcat 的地方。请注意,与之前的状态相反,我没有说任何关于应用程序上下文的内容。
http://app1.example.com/ -> http://localhost:8080
http://app2.example.com/ -> http://localhost:8080
虚拟主机配置
所以现在要区分哪个子域应该触发哪个应用程序我使用tomcat的虚拟主机(阅读更多here)。
更新的 ./tomcat/conf/server.xml 看起来像这样
<Host name="app1.example.pl" appBase="app1"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="app1_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
<Host name="app2.example.pl" appBase="app2"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="apps2_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
战争地点
现在,我将两个应用程序的 war 文件分别放在文件夹 app1 和 app2 中,而不是 webapps(它们与 webapp 文件夹放在同一个父文件夹中)。最后要删除 ContextPath,我们希望它们被部署为 ROOT 应用程序,因此对于两个应用程序的战争都应该命名为 ROOT.war
结论
我相信这比破解 Spring Security 要好得多。它还允许您在 SpringMVC 中使用“redirect:”和亲属路径。
【讨论】:
【参考方案3】:我发现使用 DefaultRedirectStrategy 是不够的,因为它会丢失协议信息(从 HTTP 重定向到 HTTPS)。我仍然需要覆盖一堆 spring 对象来设置我自己的 RedirectStrategy 但至少这适用于删除上下文路径。
public class NoContextPathRedirectStrategy implements RedirectStrategy
private static final Logger logger = LoggerFactory.getLogger(NoContextPathRedirectStrategy.class);
@Override
public void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url) throws IOException
String redirectUrl = calculateRedirectUrl(request.getContextPath(), url);
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))
return url;
else
int contextPathIndex = url.indexOf(contextPath);
int contextPathLength = contextPath.length();
// check to see if there is a context path in this url
if (contextPathIndex >= 0)
// strip out the context path
url = url.substring(0, contextPathIndex) + url.substring(contextPathIndex + contextPathLength);
// check to see if there is a leading /
if (url.length() > 1 && url.charAt(0) == '/')
// remove the leading slash
url = url.substring(1);
return url;
【讨论】:
以上是关于Spring Security - 更改 RedirectStrategy 的所有实例的主要内容,如果未能解决你的问题,请参考以下文章
更改 Spring Security WebFilter 的顺序
Spring Security:添加“伪登录”以更改用户信息