nginx转发后,CAS拿不到正确端口的问题

2021-10-12  本文已影响0人  fzhyzamt

访问路径:用户 -> nginx -> tomcat
在直接访问tomcat时没有问题,但经过nginx后cas无法拿到端口,导致拿到ticket后跳转错误。

http://portal.example.com/portalcas/login;jsessionid=XXXX?service=http://example.com:8080/cas
302 http://example.com:8080/cas?ticket=ST-1234-XXXXXX-portal.example.com
302 http://example.com/

查看cas中跳转的逻辑:

org.apache.shiro.web.filter.authc.AuthenticationFilter
    protected void issueSuccessRedirect(ServletRequest request, ServletResponse response) throws Exception {
        WebUtils.redirectToSavedRequest(request, response, getSuccessUrl());
    }
org.apache.shiro.web.util.WebUtils
    public static void issueRedirect(ServletRequest request, ServletResponse response, String url, Map queryParams, boolean contextRelative, boolean http10Compatible) throws IOException {
        RedirectView view = new RedirectView(url, contextRelative, http10Compatible);
        view.renderMergedOutputModel(queryParams, toHttp(request), toHttp(response));
    }
org.apache.shiro.web.servlet.ShiroHttpServletResponse
    public String encodeRedirectURL(String url) {
        if (isEncodeable(toAbsolute(url))) {
            return toEncoded(url, request.getSession().getId());
        } else {
            return url;
        }
    }
    private String toAbsolute(String location) {
        boolean leadingSlash = location.startsWith("/");

        if (leadingSlash || !hasScheme(location)) {

            StringBuilder buf = new StringBuilder();

            String scheme = request.getScheme();
            String name = request.getServerName();
            int port = request.getServerPort();

            try {
                buf.append(scheme).append("://").append(name);
                if ((scheme.equals("http") && port != 80)
                        || (scheme.equals("https") && port != 443)) {
                    buf.append(':').append(port);
                }
                if (!leadingSlash) {
                    String relativePath = request.getRequestURI();
                    int pos = relativePath.lastIndexOf('/');
                    relativePath = relativePath.substring(0, pos);

                    String encodedURI = URLEncoder.encode(relativePath, getCharacterEncoding());
                    buf.append(encodedURI).append('/');
                }
                buf.append(location);
            } catch (IOException e) {
                IllegalArgumentException iae = new IllegalArgumentException(location);
                iae.initCause(e);
                throw iae;
            }

            return buf.toString();

        } else {
            return location;
        }
    }

其中的request.getServerPort();是获取请求头中的端口,如果nginx转发时没有带上就会是默认的80

方案一

不推荐
nginx中将proxy_set_header Host $host;改为proxy_set_header Host $host:$server_port;proxy_set_header Host $http_host;

方案二

nginx中添加如下头:

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_addr;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Proto $scheme;

如果是springboot集成的tomcat,在application.yml中如下配置:

server:
  tomcat:
    remoteip:
      protocol-header: X-Forwarded-Proto
      remote-ip-header: X-Forwarded-For
      protocol-header-https-value: https

如果直接配置tomcat的xml:

<Engine>
    <Valve className="org.apache.catalina.valves.RemoteIpValve" 
    remoteIpHeader="X-Forwarded-For" 
    protocolHeader="X-Forwarded-Proto" 
    protocolHeaderHttpsValue="https"/>
</Engine >

当开启了X-Forwarded-Proto时,会去获取X-Forwarded-Port的值,获取不到就会使用默认的80、443.

参考:
https://serverfault.com/questions/363159/nginx-proxy-pass-redirects-ignore-port
http://thomaslau.xyz/2019/10/28/2019-10-28-nginx_springsecurity_cas_error/
https://blog.csdn.net/goldenfish1919/article/details/78815192
https://blog.csdn.net/heavenick/article/details/51924774

上一篇下一篇

猜你喜欢

热点阅读