访问路径:用户 -> 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
网友评论