上一篇咱們說了在web項目中了和spring整合以後,如何進行對應Filter的初始化,若是你還沒看過,請點擊 《CAS源碼追蹤系列一:Filter的初始化》。 本篇咱們來看看在初始化完成之後,cas-client是如何處理請求的。java
源碼地址:https://github.com/apereo/java-cas-clientgit
如何你還不太清楚sso的原理,你能夠看看這篇文章《單點登陸原理與簡單實現》。
當訪問系統受保護的資源時,cas的過濾器AuthenticationFilter會對它進行攔截,發現用戶沒有登陸(系統中沒有對應的session信息),就會跳轉到統一登陸頁面。不然調用FilterChain中下一個Filter。github
來看AuthenticationFilter的web
doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,final FilterChain filterChain)
if (isRequestUrlExcluded(request)) {
logger.debug("Request is ignored.");
filterChain.doFilter(request, response);
return;
}
判斷請求是不是不須要被攔截,是,則進行直接調用FilterChain中下一個Filter,不然向下執行
來看看isRequestUrlExcluded方法spring
private boolean isRequestUrlExcluded(final HttpServletRequest request) {
/
是否有忽略url匹配類,
在AuthenticationFilter的initInternal(final FilterConfig filterConfig)進行初始化
*/
if (this.ignoreUrlPatternMatcherStrategyClass == null) {
return false;
}session
final StringBuffer urlBuffer = request.getRequestURL(); if (request.getQueryString() != null) { urlBuffer.append("?").append(request.getQueryString());//拼裝url } final String requestUri = urlBuffer.toString(); /* *匹配url是否是不用被攔截,攔截規則須要用戶在配置文件配置, *在AuthenticationFilter的initInternal(final FilterConfig *filterConfig)加載到ignoreUrlPatternMatcherStrategyClass */ return this.ignoreUrlPatternMatcherStrategyClass.matches(requestUri); }
final HttpSession session = request.getSession(false);//獲取用戶session,注意到參數是false,表示session沒有的話不新建一個session
final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null;//若是有session,則從CONST_CAS_ASSERTION屬性值獲取斷言
若是session不存在或者session中CONST_CAS_ASSERTION爲空則表明用戶還未登陸,則須要繼續向下執行,不然執行下一個Filter。
final String serviceUrl = constructServiceUrl(request, response);//解析請求地址
該方法最終調用app
CommonUtils.constructServiceUrl(final HttpServletRequest request, final HttpServletResponse response,
final String service, final String serverNames, final String serviceParameterName,
final String artifactParameterName, final boolean encode);
@param service: 服務地址或者說是你要請求的地址,該方法更樂意你提供這個參數(可在配置文件配置)
@param serverName:服務名,如http://localhost:8080學習
if (CommonUtils.isNotBlank(service)) {
return encode ? response.encodeURL(service) : service;
}
代碼一開始先對server參數進行校驗,如何不爲空,直接返回。這也就是爲何爲何指望你配置這個參數,邏輯簡單啊。 若是不爲空,則須要對請求的url進行解析。ui
final String serverName = findMatchingServerName(request, serverNames);
final URIBuilder originalRequestUrl = new URIBuilder(request.getRequestURL().toString(), encode);
originalRequestUrl.setParameters(request.getQueryString());this
final URIBuilder builder; if (!serverName.startsWith("https://") && !serverName.startsWith("http://")) { String scheme = request.isSecure() ? "https://" : "http://"; builder = new URIBuilder(scheme + serverName, encode); } else { builder = new URIBuilder(serverName, encode); } if (builder.getPort() == -1 && !requestIsOnStandardPort(request)) { builder.setPort(request.getServerPort()); } builder.setEncodedPath(builder.getEncodedPath() + request.getRequestURI());
根據url獲取請求參數(request.getQueryString())時,會判斷有沒有攜帶ticket參數且必須在第一個位置(location==0),若是是就直接返回以前拼裝的url,不然繼續拼裝參數 。
final List
if (!serviceParameterNames.isEmpty() && !originalRequestUrl.getQueryParams().isEmpty()) {
for (final URIBuilder.BasicNameValuePair pair : originalRequestUrl.getQueryParams()) {
String name = pair.getName();
if (!name.equals(artifactParameterName) && !serviceParameterNames.contains(name)) {
if (name.contains("&") || name.contains("=") ){
URIBuilder encodedParamBuilder = new URIBuilder();
encodedParamBuilder.setParameters(name);
for (final URIBuilder.BasicNameValuePair pair2 :encodedParamBuilder.getQueryParams()){
String name2 = pair2.getName();
if (!name2.equals(artifactParameterName) && !serviceParameterNames.contains(name2)) {
builder.addParameter(name2, pair2.getValue());
}
}
} else {
builder.addParameter(name, pair.getValue());
}
}
}
主要就是過濾掉名爲「ticket」的參數。
再回到AuthenticationFilter
final String ticket = retrieveTicketFromRequest(request);//獲取請求中的ticket
而後判斷若是有ticket並且設置了網關,就直接調用下一個Filter,不然繼續向下執行。
final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl,
getProtocol().getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
根據已有的數據構造一個重定向url,也就是對於請求認證失敗的時候跳轉的地址,相似於https://localhost:8443/cas/login?service=https%3A%2F%2Flocalhost%3A8443%2Ftest%3Ftest%3D12456%26sss%3D111。「?」前面部分爲認證中心登陸頁面,後面則爲登陸成功以後要跳轉的地址。
最後一步就是執行重定向。
總結
這一片咱們簡單分析了cas-client如何處理請求,對於認證成功的繼續執行下一個Filter,失敗的則跳轉到登陸頁面。下一篇咱們會講cas-server端是如何處理登陸的。
平時的學習過程記錄一下,沒有那麼高深,但願能幫到你們,與君共同進步。我是敲代碼的小魯班,喜歡的話給個推薦,點贊,關注吧。