CAS客户端过滤器源码备忘
来源:互联网 发布:网络高清数字矩阵 编辑:程序博客网 时间:2024/06/07 14:09
AuthenticationFilter中doFilter方法源码:
01.
public
final
void
doFilter(
final
ServletRequest servletRequest,
final
ServletResponse servletResponse,
final
FilterChain filterChain)
throws
IOException, ServletException {
02.
final
HttpServletRequest request = (HttpServletRequest) servletRequest;
03.
final
HttpServletResponse response = (HttpServletResponse) servletResponse;
04.
final
HttpSession session = request.getSession(
false
);
05.
final
Assertion assertion = session !=
null
? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) :
null
;
06.
07.
// 如果session中的CONST_CAS_ASSERTION(即"_const_cas_assertion_")不为空,则跳过此过滤器
08.
if
(assertion !=
null
) {
09.
filterChain.doFilter(request, response);
10.
return
;
11.
}
12.
13.
final
String serviceUrl = constructServiceUrl(request, response);
14.
final
String ticket = CommonUtils.safeGetParameter(request,getArtifactParameterName());
15.
final
boolean
wasGatewayed =
this
.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
16.
17.
// 如果ticket参数不为空,则跳过此过滤器
18.
if
(CommonUtils.isNotBlank(ticket) || wasGatewayed) {
19.
filterChain.doFilter(request, response);
20.
return
;
21.
}
22.
23.
final
String modifiedServiceUrl;
24.
25.
log.debug(
"no ticket and no assertion found"
);
26.
if
(
this
.gateway) {
27.
log.debug(
"setting gateway attribute in session"
);
28.
modifiedServiceUrl =
this
.gatewayStorage.storeGatewayInformation(request, serviceUrl);
29.
}
else
{
30.
modifiedServiceUrl = serviceUrl;
31.
}
32.
33.
if
(log.isDebugEnabled()) {
34.
log.debug(
"Constructed service url: "
+ modifiedServiceUrl);
35.
}
36.
37.
final
String urlToRedirectTo = CommonUtils.constructRedirectUrl(
this
.casServerLoginUrl, getServiceParameterName(), modifiedServiceUrl,
this
.renew,
this
.gateway);
38.
39.
if
(log.isDebugEnabled()) {
40.
log.debug(
"redirecting to "
" + urlToRedirectTo + "
""
);
41.
}
42.
43.
// 否则跳转到CAS Server登录页面
44.
response.sendRedirect(urlToRedirectTo);
45.
}
通过源码可以看出这个过滤器的处理流程:
如果session中包含name为"_const_cas_assertion_"的属性,也就是用户已经登录过了,则跳过此过滤器。
如果ticket参数不为空,即可能是登录后跳转回来的URL,则跳过此过滤器。(注意,AuthenticationFilter只判断ticket是否为空,并不做ticket合法校验,也就是随便输入一个ticket参数在URL中都可以通过此过滤器。而负责校验ticket的是第二个过滤器:TicketValidationFilter 。)
如果上面两个条件都不满足,也就是既没有"_const_cas_assertion_"的session又没有ticket参数,则跳转到XML配置的casServerLoginUrl,让用户到CAS Server上登录,并在URL加上一个参数service(即XML配置的serverName加上相对路径,用于登录成功后返回登录前的页面)。
下面来测试一下,web.xml先只配置一个过滤器,去掉其他过滤器:
在浏览器中输入地址http://localhost:9999/a/b/c并打开,会跳到登录页面,也就是XML中配置的casServerLoginUrl,并加上一个用于返回登录前页面的参数,这个参数由XML配置的serverName加上路径/a/b/c生成,即http://localhost:8080/cas/login?service=http://localhost:9999/a/b/c。再次页面输入用户名、密码登录,如果登录成功,则跳转到service参数指定的页面,并加上一个参数ticket,即http://localhost:9999/a/b/c?ticket=ST-12-1XGQRUtFnwtqQxdNLOdv-cas01.example.org。
这里可以再测试一下AuthenticationFilter是否校验ticket合法性。例如在浏览器中打开http://localhost:9999/a/b/c?ticket=123,其中ticket参数是随便写的,肯定不是合法的,但是访问可以直接进入页面,不再需要登录。也就是AuthenticationFilter只判断ticket是否为空,并不校验是否合法。
2、TicketValidationFilter
由于TicketValidationFilter、Cas20ProxyReceivingTicketValidationFilter都继承自AbstractTicketValidationFilter,下面看AbstractTicketValidationFilter中的doFilter方法源码:
01.
public
final
void
doFilter(
final
ServletRequest servletRequest,
final
ServletResponse servletResponse,
final
FilterChain filterChain)
throws
IOException, ServletException {
02.
03.
if
(!preFilter(servletRequest, servletResponse, filterChain)) {
04.
return
;
05.
}
06.
07.
final
HttpServletRequest request = (HttpServletRequest) servletRequest;
08.
final
HttpServletResponse response = (HttpServletResponse) servletResponse;
09.
final
String ticket = CommonUtils.safeGetParameter(request, getArtifactParameterName());
10.
11.
// 如果ticket不为空,则校验此ticket,否则直接跳过此过滤器
12.
if
(CommonUtils.isNotBlank(ticket)) {
13.
if
(log.isDebugEnabled()) {
14.
log.debug(
"Attempting to validate ticket: "
+ ticket);
15.
}
16.
17.
try
{
18.
// 校验ticket,校验失败抛出异常
19.
final
Assertion assertion =
this
.ticketValidator.validate(ticket, constructServiceUrl(request, response));
20.
21.
if
(log.isDebugEnabled()) {
22.
log.debug(
"Successfully authenticated user: "
+ assertion.getPrincipal().getName());
23.
}
24.
25.
request.setAttribute(CONST_CAS_ASSERTION, assertion);
26.
27.
if
(
this
.useSession) {
28.
// 设置session中的CONST_CAS_ASSERTION(即"_const_cas_assertion_")属性
29.
request.getSession().setAttribute(CONST_CAS_ASSERTION, assertion);
30.
}
31.
onSuccessfulValidation(request, response, assertion);
32.
33.
if
(
this
.redirectAfterValidation) {
34.
log. debug(
"Redirecting after successful ticket validation."
);
35.
36.
// URL去掉ticket参数并跳转
37.
response.sendRedirect(constructServiceUrl(request, response));
38.
return
;
39.
}
40.
}
catch
(
final
TicketValidationException e) {
41.
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
42.
log.warn(e, e);
43.
44.
onFailedValidation(request, response);
45.
46.
if
(
this
.exceptionOnValidationFailure) {
47.
throw
new
ServletException(e);
48.
}
49.
50.
return
;
51.
}
52.
}
53.
54.
filterChain.doFilter(request, response);
55.
56.
}
通过源码可以看出这个过滤器的处理流程:
如果有ticket参数,校验ticket是否合法(不合法则异常:org.jasig.cas.client.validation.TicketValidationException: CAS Server could not validate ticket)。
如果合法则在session加入"_const_cas_assertion_",并再次跳转,这次跳转主要就是去掉ticket参数,即从http://localhost:9999/a/b/c?ticket=ST-12-1XGQRUtFnwtqQxdNLOdv-cas01.example.org跳转到http://localhost:9999/a/b/c。(这样做有个好处就是如果用户F5刷新页面,由于已经没有ticket参数,不会再次去校验ticket,而同一个ticket只能使用一次,再次去CAS服务器校验会出现TicketValidationException异常。)
如果没有ticket参数,则直接跳过此过滤器(没有ticket参数的话就一定是session中包含"_const_cas_assertion_"的属性,否则连第一个过滤器AuthenticationFilter都无法通过)。
整理一下整个登录流程:
第一次请求应用服务器:
当用户第一次访问应用服务器的URL,由于session中没有"_const_cas_assertion_"且参数中没有ticket,会被AuthenticationFilter跳转到CAS服务器的登录页面。
第二次请求应用服务器:
在CAS服务器的登录页面成功登录以后,会跳转到应用服务器登录前的页面,但是加上了一个参数ticket。此次请求由于有ticket参数,通过了AuthenticationFilter,但是TicketValidationFilter会对ticket进行校验,校验成功后,会在session中加入"_const_cas_assertion_",再去掉ticket参数进行一次跳转。
第三次请求应用服务器:
此时由于session中已经有了"_const_cas_assertion_",会通过AuthenticationFilter,由于没有ticket参数,也通过了TicketValidationFilter,也就是可以正常显示出这个页面了。以后再请求应用服务器就和这次一样了,由于session包含"_const_cas_assertion_"即可正常访问。
- CAS客户端过滤器源码备忘
- CAS客户端基本配置备忘
- 自定义cas客户端核心过滤器AuthenticationFilter
- CAS-Client客户端研究(六)-各种过滤器参数说明
- CAS Java客户端登录相关过滤器的处理流程
- CAS Java客户端登录相关过滤器的处理流程
- CAS单点登录源码解析之【客户端】
- 1、[置顶] CAS单点登录源码解析之【客户端】
- SSO之CAS备忘
- SSO单点登录系列1:cas客户端源码分析cas-client-java-2.1.1.jar
- cas客户端,shiro-cas整合
- MINA源码分析---对客户端设置连接间隔时间的过滤器
- CAS 客户端配置
- Cas 客户端配置
- 部署CAS应用-客户端
- play cas 客户端配置
- cas 客户端配置说明
- cas 客户端配置
- PHP与MYSQL实现用户登录注销
- 求Fibonacci数列前40个数
- New package not yet registered with the system. Waiting 3 seconds before next attempt解决方案
- 剑指Offer:旋转数组的最小数字
- 深入解析array_merge函数的用法 php
- CAS客户端过滤器源码备忘
- 【中间件】(一):中间件原来和分布式有关系……
- (一)Java虚拟机基础详解
- RAM评估方法详解
- notify()和notifyAll()的区别
- HDU 1198 Farm Irrigation (并查集)
- HQL查询和Criteria查询
- JAVA EE7 Servlet 3.1新规范与中文乱码问题
- spring-boot-maven-plugin 插件的作用