概述
客户端是如何向服务端发起请求的
前面客户端部分讲过,客户端的web.xml里配置了五个filter。下文中会使用序号来表示,具体的过滤器名称可以看上一章节。
1. 调用第1个filter
首先进入第一个filter:SingleSignOutFilter,因为现在是进行登录认证,没有登出请求,所以什么都没做,进入下一个filter。
2. 调用第2个filter
*AuthenticationFilter.java*
public class AuthenticationFilter extends AbstractCasFilter {
public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
if (isRequestUrlExcluded(request)) {
logger.debug("Request is ignored.");
filterChain.doFilter(request, response);
return;
}
//此时重定向回来,还没有创建session,因此不能获取到assertion
final HttpSession session = request.getSession(false);
final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null;
if (assertion != null) {
filterChain.doFilter(request, response);
return;
}
final String serviceUrl = constructServiceUrl(request, response);
final String ticket = retrieveTicketFromRequest(request);
final boolean wasGatewayed = this.gateway && this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
//由于CAS服务端认证成功后重定向到客户端会带ticket参数,因此ticket不为空进入此代码中
if (CommonUtils.isNotBlank(ticket) || wasGatewayed) {
filterChain.doFilter(request, response);
return;//执行到这
}
......
}
执行到对ticket的判断,CAS单点登录服务端认证成功后会带上ticket重定向到客户端,因为此时ticket不为空,所以进入下一个filter。
4. 调用第3个filter
该类Cas20ProxyReceivingTicketValidationFilter在org.jasig.cas.client.validation包中继承自AbstractTicketValidationFilter。首先执行doFilter方法,注意doFilter是在父类中进行调用的,我们先分析父类方法。
*AbstractTicketValidationFilter.java*
public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
if (!preFilter(servletRequest, servletResponse, filterChain)) {
return;
}
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
//从请求中获取到ticket
final String ticket = retrieveTicketFromRequest(request);
//判断ticket是否为空
if (CommonUtils.isNotBlank(ticket)) {
logger.debug("Attempting to validate ticket: {}", ticket);
try {
//通过ticket和service去校验ticket,并返回assertion用户认证信息
final Assertion assertion = this.ticketValidator.validate(ticket,
constructServiceUrl(request, response));
logger.debug("Successfully authenticated user: {}", assertion.getPrincipal().getName());
request.setAttribute(CONST_CAS_ASSERTION, assertion);
if (this.useSession) {
//如果需要使用session,则把获取到的assertion认证信息放入会话
request.getSession().setAttribute(CONST_CAS_ASSERTION, assertion);
}
onSuccessfulValidation(request, response, assertion);
if (this.redirectAfterValidation) {
//认证成功后重定向到客户端的service地址
logger.debug("Redirecting after successful ticket validation.");
response.sendRedirect(constructServiceUrl(request, response));
return;
}
} catch (final TicketValidationException e) {
logger.debug(e.getMessage(), e);
onFailedValidation(request, response);
if (this.exceptionOnValidationFailure) {
throw new ServletException(e);
}
response.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
return;
}
}
filterChain.doFilter(request, response);
}
…………
}
通过ticketValidator.validate(ticket, constructServiceUrl(request, response))对ticket进行校验。下面我们分析是如何进行ticket校验的。
5. 调用ticketValidator.validate校验ticket
AbstractUrlBasedTicketValidator类在org.jasig.cas.client.validation包中。
*AbstractUrlBasedTicketValidator.java*
public abstract class AbstractUrlBasedTicketValidator implements TicketValidator {
…………
public final Assertion validate(final String ticket, final String service) throws TicketValidationException {
//计算需要请求到CAS服务端的url地址(注意这里是普通登录模式,所以校验地址为:serviceValidate
final String validationUrl = constructValidationUrl(ticket, service);
logger.debug("Constructing validation url: {}", validationUrl);
try {
logger.debug("Retrieving response from server.");
//到CAS单点登录服务进行校验,获取返回结果
final String serverResponse = retrieveResponseFromServer(new URL(validationUrl), ticket);
if (serverResponse == null) {
throw new TicketValidationException("The CAS server returned no response.");
}
logger.debug("Server response: {}", serverResponse);
//解析从服务端获取到的信息
return parseResponseFromServer(serverResponse);
} catch (final MalformedURLException e) {
throw new TicketValidationException(e);
}
}
…………
注意retrieveResponseFromServer()会访问CAS单点登录服务端。
6. 调用retrieveResponseFromServer请求CAS单点登录服务端
AbstractCasProtocolUrlBasedTicketValidator类在org.jasig.cas.client.validation包中。
*AbstractCasProtocolUrlBasedTicketValidator.java*
public abstract class AbstractCasProtocolUrlBasedTicketValidator extends AbstractUrlBasedTicketValidator {
protected AbstractCasProtocolUrlBasedTicketValidator(final String casServerUrlPrefix) {
super(casServerUrlPrefix);
}
/**
* Retrieves the response from the server by opening a connection and merely reading the response.
*/
protected final String retrieveResponseFromServer(final URL validationUrl, final String ticket) {
return CommonUtils.getResponseFromServer(validationUrl, getURLConnectionFactory(), getEncoding());
}
}
最终调用CommonUtils.getResponseFromServer(),我们还要再往下找。
7. 调用CommonUtils.getResponseFromServer()
最终其实是通过后端发起http请求获取到cas服务端的数据。
## CommonUtils.java
public final class CommonUtils {
…………
public static String getResponseFromServer(final URL constructedUrl, final HttpURLConnectionFactory factory,
final String encoding) {
HttpURLConnection conn = null;
InputStreamReader in = null;
try {
//创建http的连接
conn = factory.buildHttpURLConnection(constructedUrl.openConnection());
if (CommonUtils.isEmpty(encoding)) {
in = new InputStreamReader(conn.getInputStream());
} else {
in = new InputStreamReader(conn.getInputStream(), encoding);
}
final StringBuilder builder = new StringBuilder(255);
int byteRead;
//通过输入流获取到服务端的响应
while ((byteRead = in.read()) != -1) {
builder.append((char) byteRead);
}
//通过流创建返回的数据
return builder.toString();
} catch (final Exception e) {
LOGGER.error(e.getMessage(), e);
throw new RuntimeException(e);
} finally {
closeQuietly(in);
if (conn != null) {
conn.disconnect();
}
}
}
…………
}
constructedUrl的传入值为:http://localhost:8080/cas/serviceValidate?ticket=ST-2-ZRix41JWjd3oHDoN3DhI-cas01.example.org&service=http%3A%2F%2Flocalhost%3A8088%2Fcas-client%2F
开始向服务端发验证请求,验证ticket,至此,完成了流程图的第5步:
后续我们就要对通过ST票据验证之后的数据进行解析以及ST验证成功和失败后返回给客户端的到底是什么信息,将在下一章节进行分析。
最后
以上就是典雅高跟鞋为你收集整理的CAS单点登录开源框架解读(八)--CAS单点登录客户端认证之客户端向服务端发起请求客户端是如何向服务端发起请求的的全部内容,希望文章能够帮你解决CAS单点登录开源框架解读(八)--CAS单点登录客户端认证之客户端向服务端发起请求客户端是如何向服务端发起请求的所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复