起因:
项目对接cas认证中心,当服务关闭或者重启,会使客户端session失效,再次请求接口则会出现302问题,后台会进行去登录的跳转,状态err_failed。
思路:
我们能不能在进行cas处理前判断当前session是否有效,通过filter
解决:
1、自定义拦截器,并添加到cas过滤器中;
2、对过期的session,通过响应一个状态码让前端处理,跳转到登录页,这里处理是刷新reload下;
1、cas拦截配置 –new CasAuthenticationFilter()
@Component
@EnableCasClient
@Order(0)
public class CasConfig extends CasClientConfigurerAdapter {
@Resource
private GlobalParamConfig globalParamConfig;
@Override
public void configureAuthenticationFilter(FilterRegistrationBean authenticationFilter) {
super.configureAuthenticationFilter(authenticationFilter);
//配置自定义过滤器
authenticationFilter.setFilter(new CasAuthenticationFilter());
authenticationFilter.addUrlPatterns("/*");
authenticationFilter.getInitParameters().put("ignorePattern", globalParamConfig.ignorePattern);
//自定义UrlPatternMatcherStrategy 过滤规则
authenticationFilter.addInitParameter("ignoreUrlPatternType", ignoreUrlPatternType);
authenticationFilter.setOrder(0);
2、自定义过滤器
@Component
public class CasAuthenticationFilter extends AbstractCasFilter {
private String casServerLoginUrl;
private boolean renew;
private boolean gateway;
private GatewayResolver gatewayStorage;
private AuthenticationRedirectStrategy authenticationRedirectStrategy;
private UrlPatternMatcherStrategy ignoreUrlPatternMatcherStrategyClass;
private static final Map<String, Class<? extends UrlPatternMatcherStrategy>> PATTERN_MATCHER_TYPES = new HashMap();
/**
* 构造方法
*/
public MyAuthenticationFilter() {
this(Protocol.CAS2);
}
protected MyAuthenticationFilter(Protocol protocol) {
super(protocol);
this.renew = false;
this.gateway = false;
this.gatewayStorage = new DefaultGatewayResolverImpl();
this.authenticationRedirectStrategy = new DefaultAuthenticationRedirectStrategy();
this.ignoreUrlPatternMatcherStrategyClass = null;
}
protected void initInternal(FilterConfig filterConfig) throws ServletException {
if (!this.isIgnoreInitConfiguration()) {
super.initInternal(filterConfig);
this.setCasServerLoginUrl(this.getString(ConfigurationKeys.CAS_SERVER_LOGIN_URL));
this.setRenew(this.getBoolean(ConfigurationKeys.RENEW));
this.setGateway(this.getBoolean(ConfigurationKeys.GATEWAY));
String ignorePattern = this.getString(ConfigurationKeys.IGNORE_PATTERN);
String ignoreUrlPatternType = this.getString(ConfigurationKeys.IGNORE_URL_PATTERN_TYPE);
Class gatewayStorageClass;
if (ignorePattern != null) {
gatewayStorageClass = (Class) PATTERN_MATCHER_TYPES.get(ignoreUrlPatternType);
if (gatewayStorageClass != null) {
this.ignoreUrlPatternMatcherStrategyClass = (UrlPatternMatcherStrategy) ReflectUtils.newInstance(gatewayStorageClass.getName(), new Object[0]);
} else {
try {
this.logger.trace("Assuming {} is a qualified class name...", ignoreUrlPatternType);
this.ignoreUrlPatternMatcherStrategyClass = (UrlPatternMatcherStrategy) ReflectUtils.newInstance(ignoreUrlPatternType, new Object[0]);
} catch (IllegalArgumentException var6) {
this.logger.error("Could not instantiate class [{}]", ignoreUrlPatternType, var6);
}
}
if (this.ignoreUrlPatternMatcherStrategyClass != null) {
this.ignoreUrlPatternMatcherStrategyClass.setPattern(ignorePattern);
}
}
gatewayStorageClass = this.getClass(ConfigurationKeys.GATEWAY_STORAGE_CLASS);
if (gatewayStorageClass != null) {
this.setGatewayStorage((GatewayResolver) ReflectUtils.newInstance(gatewayStorageClass, new Object[0]));
}
Class<? extends AuthenticationRedirectStrategy> authenticationRedirectStrategyClass = this.getClass(ConfigurationKeys.AUTHENTICATION_REDIRECT_STRATEGY_CLASS);
if (authenticationRedirectStrategyClass != null) {
this.authenticationRedirectStrategy = (AuthenticationRedirectStrategy) ReflectUtils.newInstance(authenticationRedirectStrategyClass, new Object[0]);
}
}
}
/**
* 初始化
*/
public void init() {
super.init();
CommonUtils.assertNotNull(this.casServerLoginUrl, "casServerLoginUrl cannot be null.");
}
/**
* 核心方法
*
* @param servletRequest
* @param servletResponse
* @param filterChain
* @throws IOException
* @throws ServletException
*/
public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//判断是否是不必要拦截的请求地址
if (this.isRequestUrlExcluded(request)) {
this.logger.debug("Request is ignored.");
filterChain.doFilter(request, response);
} else {
//获取session,判断session是否失效
HttpSession session = request.getSession(false);
Assertion assertion = session != null ? (Assertion) session.getAttribute("_const_cas_assertion_") : null;
if (assertion != null) {
filterChain.doFilter(request, response);
} else {
//session失效判断票据和断言
String serviceUrl = this.constructServiceUrl(request, response);
String ticket = this.retrieveTicketFromRequest(request);
boolean wasGatewayed = this.gateway && this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
if (!CommonUtils.isNotBlank(ticket) && !wasGatewayed) {
this.logger.debug("no ticket and no assertion found");
String modifiedServiceUrl;
if (this.gateway) {
this.logger.debug("setting gateway attribute in session");
modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
} else {
modifiedServiceUrl = serviceUrl;
}
//获取请求路径
this.logger.debug("Constructed service url: {}", modifiedServiceUrl);
String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, this.getProtocol().getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
//判断请求方式是否为ajax请求
String header = request.getHeader("X-Requested-With");
// String header1 = request.getHeader("x-version-type");
if ("XMLHttpRequest".equals(header)) { // || (null != header1 && header1.equals("Admin"))
//给这个请求打上标记(登录已经超时或者认证未通过)
ajaxHttpToLogin(request, response, loginUrl);
} else {
this.logger.debug("redirecting to \"{}\"", urlToRedirectTo);
this.authenticationRedirectStrategy.redirect(request, response, urlToRedirectTo);
}
/* String urls = urlToRedirectTo;
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("<script language='javascript'>window.location.href='" + urls + "/'</script>");*/
} else {
filterChain.doFilter(request, response);
}
}
}
}
/**
* ajax请求标记
*
* @param request
* @param response
* @param loginUrl
*/
private void ajaxHttpToLogin(HttpServletRequest request, HttpServletResponse response, String loginUrl) {
try {
//这里响应状态码为自定义,前端根据状态去处理
response.setStatus(ResultCodeEnum.SESSION_EXPIRED.getCode());//403 禁止
response.getWriter().print(JSONObject.toJSONString(new ResultVo<>(ResultCodeEnum.SESSION_EXPIRED, new Message("error", ResultCodeEnum.SESSION_EXPIRED.getMsg()))));
} catch (Exception e) {
e.printStackTrace();
}
}
public final void setRenew(boolean renew) {
this.renew = renew;
}
public final void setGateway(boolean gateway) {
this.gateway = gateway;
}
public final void setCasServerLoginUrl(String casServerLoginUrl) {
this.casServerLoginUrl = casServerLoginUrl;
}
public final void setGatewayStorage(GatewayResolver gatewayStorage) {
this.gatewayStorage = gatewayStorage;
}
private boolean isRequestUrlExcluded(HttpServletRequest request) {
if (this.ignoreUrlPatternMatcherStrategyClass == null) {
return false;
} else {
StringBuffer urlBuffer = request.getRequestURL();
if (request.getQueryString() != null) {
urlBuffer.append("?").append(request.getQueryString());
}
String requestUri = urlBuffer.toString();
return this.ignoreUrlPatternMatcherStrategyClass.matches(requestUri);
}
}
static {
PATTERN_MATCHER_TYPES.put("CONTAINS", ContainsPatternUrlPatternMatcherStrategy.class);
PATTERN_MATCHER_TYPES.put("REGEX", RegexUrlPatternMatcherStrategy.class);
PATTERN_MATCHER_TYPES.put("EXACT", ExactUrlPatternMatcherStrategy.class);
}
}
3、当然第一步也可以FilterRegistrationBean 设置,不一定按照上面来,如下
@Bean
public FilterRegistrationBean filterAuthenticationRegistration(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new CasAuthenticationFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setOrder(0);
return registrationBean;
}
就到这吧,ending!
感谢以下博文: