訪問路徑:用戶 -> nginx -> tomcat
在直接訪問tomcat時(shí)沒有問題埋涧,但經(jīng)過nginx后cas無法拿到端口碘勉,導(dǎo)致拿到ticket后跳轉(zhuǎn)錯(cuò)誤巷挥。
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中跳轉(zhuǎn)的邏輯:
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轉(zhuǎn)發(fā)時(shí)沒有帶上就會是默認(rèn)的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 >
當(dāng)開啟了X-Forwarded-Proto時(shí)倍宾,會去獲取X-Forwarded-Port的值,獲取不到就會使用默認(rèn)的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