【问题标题】:Spring Security - Change all instances of RedirectStrategySpring Security - 更改 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 不允许这个工作。

我是不是找错地方了?

【问题讨论】:

    标签: java spring apache tomcat spring-security


    【解决方案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;
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2010-10-29
          • 2013-11-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-08-31
          • 1970-01-01
          • 1970-01-01
          • 2012-12-23
          相关资源
          最近更新 更多