本公司使用耶鲁大学的cas做单点登录服务器,在org.jasig.cas.client.authentication.AuthenticationFilter(过滤拦截请求,进行身份验证)中在181行this.authenticationRedirectStrategy.redirect(request, response, urlToRedirectTo);出现的问题
在tomcat的web.xml中配置
<login-config>
<!-- Authorization setting for SSL -->
<auth-method>CLIENT-CERT</auth-method>
<realm-name>Client Cert Users-only Area</realm-name>
</login-config>
<security-constraint>
<!-- Authorization setting for SSL -->
<web-resource-collection >
<web-resource-name >SSL</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
http get 请求 都能被重定向到https get 上,但是 http post 请求不行,后台老是报requestMethod GET not supported,访问的post 方法变成了get
在网上看到了一篇博客,nginx中遇到此问题是如何解决的
server {
listen 80;
server_name *.snsprj.cn;
return 307 https://hostrequest_uri;
}
然而我的请求状态码为302
查询相关资料,摘自wikipedia
302 Found
要求客户端执行临时重定向(原始描述短语为“Moved Temporarily”)。[20]由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。只有在Cache-Control或Expires中进行了指定的情况下,这个响应才是可缓存的。
新的临时性的URI应当在响应的Location域中返回。除非这是一个HEAD请求,否则响应的实体中应当包含指向新的URI的超链接及简短说明。
如果这不是一个GET或者HEAD请求,那么浏览器禁止自动进行重定向,除非得到用户的确认,因为请求的条件可能因此发生变化。
注意:虽然RFC 1945和RFC 2068规范不允许客户端在重定向时改变请求的方法,但是很多现存的浏览器将302响应视作为303响应,并且使用GET方式访问在Location中规定的URI,而无视原先请求的方法。因此状态码303和307被添加了进来,用以明确服务器期待客户端进行何种反应。
307 Temporary Redirect
在这种情况下,请求应该与另一个URI重复,但后续的请求应仍使用原始的URI。 与302相反,当重新发出原始请求时,不允许更改请求方法。 例如,应该使用另一个POST请求来重复POST请求
解决办法
由于我使用的是tomcat 进行重定向的,从上文中也可以看出tomcat 默认进行的是302重定向,不符合我们的需求,那又什么办法可以解决呢?办法就是不用tomcat提供的配置,那就是我们自己后台程序处理,毕竟用人家的受限制,自己搞,想怎么弄就怎么弄。自己做的话很明显需要一个过滤器,在请求到达sevlet 之前进行处理,代码如下:
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
@WebFilter(urlPatterns="/*",filterName="HttpsFilter")
/**
* 过滤器,将http 请求转发到https请求上来
* 重定向类型:307
* @author FrankYuan
*
*/
public class HttpsFilter implements Filter{
private Logger logger = LoggerFactory.getLogger(HttpsFilter.class);
private static final String HTTPS ="https";
private static final int HTTPS_PORT = 8443;
@Override
public void destroy() {
logger.info("------------destroy HttpsFilter --------------");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
URL newUrl = null;
if(request.getScheme().equals(HTTPS)) {
chain.doFilter(request, response);
}else {
HttpServletRequest httpRequest = (HttpServletRequest)request;
HttpServletResponse httpResponse = (HttpServletResponse)response;
String queryString = httpRequest.getQueryString()==null ? "":"?"+httpRequest.getQueryString();
httpResponse.setStatus(307);
String requestUrl = httpRequest.getRequestURL().toString();
URL reqUrl = new URL(requestUrl+queryString);
logger.info("【original request-】 "+reqUrl.toString());
newUrl = new URL(HTTPS,reqUrl.getHost(),HTTPS_PORT,reqUrl.getFile());
//进行重定向
logger.info("【new request-】 "+newUrl.toString());
httpResponse.setHeader("Location", newUrl.toString());
httpResponse.setHeader("Connection", "close");
//允许所有跨域请求
httpResponse.addHeader("Access-Control-Allow-Origin", "*");
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
logger.info("------------init HttpsFilter --------------");
}
}
注意:这里又个坑,就是重定向后需要也需要解决跨域问题,不然页面ajax请求 http 地址会出现跨域问题。