同花顺
cas-client中有两个过滤器,客户端的过滤器用处在于与cas-server进行交互。
AuthenticationFilter
1、从session中获取名为CONST_CAS_ASSERTION/_const_cas_assertion_的session,判断存在与否。
存在就放行,执行下一个过滤器,不存在则重定向到认证界面。
2、判断ticket是否存在。
存在就放行,执行下一个过滤器,不存在则重定向到认证界面。
TicketValidationFilter
1、判断ticket是否存在。
存在就验证,不存在则执行下一个过滤器。
2、如果验证成功,session会以"const_cas_assertion"的名称保存assertion对象,
创建名为CONST_CAS_ASSERTION/_const_cas_assertion_的session。
继续处理下一个过滤器。
注意:cas-server认证通过后在server端留下了TGT,客户端同样的也有它自己子系统的session。
AuthenticationFilter
1、浏览器访问客户端A。
2、经过客户端A的Cas认证过滤器,在过滤器内部执行操作:
- 首先判断存在子系统session吗。
- 不存在,继续往下走。
- 判断请求中是否存在ST。
- 不存在,重定向至Cas认证界面。
3、现在已经认证成功了,再次访问客户端,同样进入Cas认证过滤器,在过滤器内部执行操作:
- 首先判断存在子系统session吗。
- 不存在,继续往下走。
- 判断请求中是否存在ST。
- 存在,放行,进入校验过滤器。
Tips:
有人很疑惑,为什么在客户端经过两次判断呢,仅仅判断session不就可以了吗?
通过源码可以发现,在第三步操作中,此时子系统中是没有session的,只有经过校验过滤器后,子系统中才有了session。
package org.jasig.cas.client.authentication;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.jasig.cas.client.util.AbstractCasFilter;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.validation.Assertion;
public class AuthenticationFilter extends AbstractCasFilter {
private String casServerLoginUrl;
private boolean renew = false;
private boolean gateway = false;
private GatewayResolver gatewayStorage = new DefaultGatewayResolverImpl();
public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
HttpSession session = request.getSession(false);
//判断子系统中是否存在session
Assertion assertion = session != null ? (Assertion)session.getAttribute("_const_cas_assertion_") : null;
if (assertion != null) {
filterChain.doFilter(request, response);
} else {
//目标地址
String serviceUrl = this.constructServiceUrl(request, response);
//判断请求中是否存在ST
String ticket = CommonUtils.safeGetParameter(request, this.getArtifactParameterName());
boolean wasGatewayed = this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
//如果ST存在,则放行;不存在,则重定向至Cas认证界面
if (!CommonUtils.isNotBlank(ticket) && !wasGatewayed) {
this.log.debug("no ticket and no assertion found");
String modifiedServiceUrl;
if (this.gateway) {
this.log.debug("setting gateway attribute in session");
modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
} else {
modifiedServiceUrl = serviceUrl;
}
if (this.log.isDebugEnabled()) {
this.log.debug("Constructed service url: " + modifiedServiceUrl);
}
//Cas认证界面
String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, this.getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
if (this.log.isDebugEnabled()) {
this.log.debug("redirecting to \"" + urlToRedirectTo + "\"");
}
response.sendRedirect(urlToRedirectTo);
} else {
//存在ST,放行。
filterChain.doFilter(request, response);
}
}
}
}
TicketValidationFilter
1、访问客户端的请求,经过了第一个过滤器,说明已经是认证过的,但是要判断一下ST是否是亲生的,即校验ST。
2、校验通过,存入Session,重定向至目标服务地址。
package org.jasig.cas.client.validation;
import java.io.IOException;
import javax.net.ssl.HostnameVerifier;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jasig.cas.client.util.AbstractCasFilter;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.util.ReflectUtils;
public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
private TicketValidator ticketValidator;
private boolean redirectAfterValidation = false;
private boolean exceptionOnValidationFailure = true;
private boolean useSession = true;
public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
if (this.preFilter(servletRequest, servletResponse, filterChain)) {
//将servletRequest,servletResponse强转为HttpServletRequest ,HttpServletResponse 。
//过滤器中为ServletRequest,ServletResponse,但是拦截器以及我们的Controller中使用的都是HttpServletRequest,HttpServletResponse。
//增加了针对于Http协议的方法。
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
//获取ST
String ticket = CommonUtils.safeGetParameter(request, this.getArtifactParameterName());
//判断ST是否为空,不为空进行校验。
if (CommonUtils.isNotBlank(ticket)) {
if (this.log.isDebugEnabled()) {
this.log.debug("Attempting to validate ticket: " + ticket);
}
try {
Assertion assertion = this.ticketValidator.validate(ticket, this.constructServiceUrl(request, response));
if (this.log.isDebugEnabled()) {
this.log.debug("Successfully authenticated user: " + assertion.getPrincipal().getName());
}
//校验通过,request设置assertion
request.setAttribute("_const_cas_assertion_", assertion);
if (this.useSession) {
//根据过滤器参数设置,判断true/false
request.getSession().setAttribute("_const_cas_assertion_", assertion);
}
this.onSuccessfulValidation(request, response, assertion);
if (this.redirectAfterValidation) {
this.log.debug("Redirecting after successful ticket validation.");
//重定向至目标服务地址
response.sendRedirect(this.constructServiceUrl(request, response));
return;
}
} catch (TicketValidationException var8) {
response.setStatus(403);
this.log.warn(var8, var8);
this.onFailedValidation(request, response);
if (this.exceptionOnValidationFailure) {
throw new ServletException(var8);
}
return;
}
}
filterChain.doFilter(request, response);
}
}
}