Spring Security - 更改RedirectStrategy的所有实例

时间:2015-09-15 03:44:21

标签: java spring apache tomcat spring-security

我有一个运行多个WAR文件的tomcat实例。 tomcat实例被代理在Apache服务器后面,以便剥离上下文路径。相反,我正在使用子域名:

基本上,我的设置如下:

http://localhost:8080/app1 -> http://app1.example.com/
http://localhost:8080/app2 -> http://app2.example.com/

我需要做的是使所有重定向上下文相对,因为我不再在URL中包含上下文路径。我注意到Spring Security允​​许将重定向设置为" context related"使用默认类DefaultRedirectStrategy。为了使重定向工作正常,我必须覆盖多个对象,以便我可以简单地将默认的DefaultRedirectStrategy实例与contextRelative = false交换到我自己创建的DefaultRedirectStrategy实例,并使用contextRelative = true。

有没有一种更简单的方法可以告诉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;
}

^这太简单了。不知道为什么春天不能让它发挥作用。

我找错了地方吗?

3 个答案:

答案 0 :(得分:1)

我一直在努力解决同样的问题。尝试覆盖Spring Security的AuthenticationEntryPoint和SuccessHandler,以便他们使用没有Context Path的URL。当它让我感到震惊的时候,我的子域配置基本上就是说,每当有人打开http://app1.example.com/时,他/她应该被重定向到http://example.com/app1,所以就Tomcat如何看到网址以及Spring Security的情况而言确实存在。因此,也许不是在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位置

现在我将两个应用程序的war文件分别放在app1和app2文件夹中(而不是webapps)(它们与webapp文件夹放在同一个父文件夹中)。最后要删除ContextPath,我们希望它们被部署为ROOT应用程序,因此对于两个应用程序来说战争应该命名为ROOT.war

结论

我相信这比解决Spring Security更好的解决方案。同样,它允许您在SpringMVC中使用“redirect:”和亲戚路径。

答案 1 :(得分:0)

我发现使用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;
        }
    }
}

答案 2 :(得分:0)

确实,您不能仅通过定义新的 DefaultRedirectStrategy 来更改 @Bean

那,我想这太全球化了

您可以改为使用 AbstractAuthenticationTargetUrlRequestHandler.redirectStrategy 的另一个实例通过其 DefaultRedirectStrategy 更改 public void setRedirectStrategy(RedirectStrategy redirectStrategy)

@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
  }

  //
}