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 &quot;%r&quot; %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 &quot;%r&quot; %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:如何更改默认用户和密码?

登录时更改spring security中的用户名

Spring Security:添加“伪登录”以更改用户信息

Spring Security - 更改 RedirectStrategy 的所有实例

如何在 Spring Security 中更改登录 URL