CAS项目登录流程介绍(二)
来源:互联网 发布:js将对象转换成字符串 编辑:程序博客网 时间:2024/05/22 16:43
CAS项目登录流程介绍(二)
上一篇介绍了cas的登陆流程,因为cas属于第三方登陆系统,用户在经过cas认证后会跳会原来用户访问的资源。
所以就会存在外部系统会和cas系统进行一系列的授权确认,保证用户是有权限访问现有资源的。
在应用端配置一些cas相关的filter
<bean id="casSingleSignOutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter" /><bean id="casAuthenticationFilter" class="org.jasig.cas.client.authentication.AuthenticationFilter"><dynamic:property-config name="casServerLoginUrl" param-key="${config.cas.login.url}" default-value="http://${domain}/cas/login" /><dynamic:property-config name="serverName" param-key="${config.server.url}" default-value="http://${domain}" /></bean><bean id="casValidationFilter" class="org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter"><property name="ticketValidator"><bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator" p:encoding="UTF-8"><dynamic:constructor-config name="casServerUrlPrefix"param-key="${config.cas.url}" default-value="http://${domain}/cas" /></bean></property><dynamic:property-config name="serverName" param-key="${config.server.url}" default-value="http://${domain}" /><dynamic:property-config name="casServerLoginUrl" param-key="${config.cas.login.url}" default-value="http://${domain}/cas/login" /></bean><bean id="casAssertionThreadLocalFilter" class="org.jasig.cas.client.util.AssertionThreadLocalFilter" />
下面我来一个一个解释下这些filter的工作内容。
1.casSingleSignOutFilter
这个是单点登出功能,当用户在他处登出的时候就会在cas内部注销一切票据(tgt,st),而st和每个外部应用有关。所以登出时,cas会向所有外部应用发出一段saml,告诉这些应用该用户的票据失效了。
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException { final HttpServletRequest request = (HttpServletRequest) servletRequest; if (handler.isTokenRequest(request)) { handler.recordSession(request); } else if (handler.isLogoutRequest(request)) { handler.destroySession(request); // Do not continue up filter chain return; } else { log.trace("Ignoring URI " + request.getRequestURI()); } filterChain.doFilter(servletRequest, servletResponse); }
public void recordSession(final HttpServletRequest request) { final HttpSession session = request.getSession(true); final String token = CommonUtils.safeGetParameter(request, this.artifactParameterName); if (log.isDebugEnabled()) { log.debug("Recording session for token " + token); } try { this.sessionMappingStorage.removeBySessionById(session.getId()); } catch (final Exception e) { // ignore if the session is already marked as invalid. Nothing we can do! } sessionMappingStorage.addSessionById(token, session); }
public void destroySession(final HttpServletRequest request) { final String logoutMessage = CommonUtils.safeGetParameter(request, this.logoutParameterName); if (log.isTraceEnabled()) { log.trace ("Logout request:\n" + logoutMessage); } final String token = XmlUtils.getTextForElement(logoutMessage, "SessionIndex"); if (CommonUtils.isNotBlank(token)) { final HttpSession session = this.sessionMappingStorage.removeSessionByMappingId(token); if (session != null) { String sessionID = session.getId(); if (log.isDebugEnabled()) { log.debug ("Invalidating session [" + sessionID + "] for token [" + token + "]"); } try { session.invalidate(); } catch (final IllegalStateException e) { log.debug("Error invalidating session.", e); } } } }当用户的token不是登出请求时,调用recordSession,登出调用destroySession。我们可以看到其内部使用一个SessionMappingStorage对象维护session和st的关系。
而无论登出还是其他行为,cas等会带上st参数与外部应用发生交互。当登出是,这个filter做两件式意识移除SessionMappingStorage相应的session,而是将这个session失效。
2.casAuthenticationFilter
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; 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 = CommonUtils.safeGetParameter(request,getArtifactParameterName()); final boolean wasGatewayed = this.gatewayStorage.hasGatewayedAlready(request, serviceUrl); if (CommonUtils.isNotBlank(ticket) || wasGatewayed) { filterChain.doFilter(request, response); return; } final String modifiedServiceUrl; log.debug("no ticket and no assertion found"); if (this.gateway) { log.debug("setting gateway attribute in session"); modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl); } else { modifiedServiceUrl = serviceUrl; } if (log.isDebugEnabled()) { log.debug("Constructed service url: " + modifiedServiceUrl); } final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway); if (log.isDebugEnabled()) { log.debug("redirecting to \"" + urlToRedirectTo + "\""); } response.sendRedirect(urlToRedirectTo); }这个流程还是分成两部分。如果有st则进入下一个流程。如果无则重定向到cas/login服务,前面对这个服务介绍过是个weblfow,在拥有tgt情况下会生成st跳回,如果没有tgt那就必须输入用户名密码再跳回。
在跳回后url一定会用st参数所以,直接进入下一个filter
3.casValidationFilter
这是验证st的过程,客户端拿到st需要确保这个st是否是cas正确签发的。
这里直接贴核心方法dofilter,在他的父类中
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; final String ticket = CommonUtils.safeGetParameter(request, getArtifactParameterName()); if (CommonUtils.isNotBlank(ticket)) { if (log.isDebugEnabled()) { log.debug("Attempting to validate ticket: " + ticket); } try { final Assertion assertion = this.ticketValidator.validate(ticket, constructServiceUrl(request, response)); if (log.isDebugEnabled()) { log.debug("Successfully authenticated user: " + assertion.getPrincipal().getName()); } request.setAttribute(CONST_CAS_ASSERTION, assertion); if (this.useSession) { request.getSession().setAttribute(CONST_CAS_ASSERTION, assertion); } onSuccessfulValidation(request, response, assertion); if (this.redirectAfterValidation) { log. debug("Redirecting after successful ticket validation."); response.sendRedirect(constructServiceUrl(request, response)); return; }....................................这里客户端会将st作为参数,访问cas的cas/serviceValidate服务,返回assertion。如果不正确会抛出异常,如果正确则在request放入CONST_CAS_ASSERTION参数。只要参数存在,用户一次的访问行为将不再需要认证。
4.casAssertionThreadLocalFilter
这个filter做的事情很简单,将request中的assertion拿出来,放入一个threadlocal变量中,供其他的filter使用,最后再将filter清楚。
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException { final HttpServletRequest request = (HttpServletRequest) servletRequest; final HttpSession session = request.getSession(false); final Assertion assertion = (Assertion) (session == null ? request.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION) : session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION)); try { AssertionHolder.setAssertion(assertion); filterChain.doFilter(servletRequest, servletResponse); } finally { AssertionHolder.clear(); } }
- CAS项目登录流程介绍(二)
- CAS项目登录流程介绍(一)
- CAS 服务端登录验证流程(二)
- 单点登录(二)cas服务端介绍
- CAS 服务端登录验证流程(一)
- CAS 服务端登录验证流程(三)
- CAS 服务端登录验证流程(四)
- CAS登录流程详解
- CAS 登录流程
- cas 单点登录流程
- cas入门之六:cas 登录流程(下)
- cas入门之六:cas 登录流程(下)
- CAS项目介绍(三)
- cas单点登录介绍
- 单点登录-CAS介绍
- CAS单点登录执行流程
- 匿名项目连载(二)--->登录流程
- CAS单点登录(一)---CAS介绍
- 使用 JCaptcha 开发图形和声音验证码
- CUDA矩阵乘法——VS2010中使用CUDA示例
- android jni开发
- 开发日志:注意struts标签的注释
- 将博客搬至CSDN
- CAS项目登录流程介绍(二)
- 《Oracle Applications DBA 基础》- 7-8 OAM及系统管理
- makefile概述
- spring的定时任务
- 使用MediaRecorder录制音频
- Linux下多任务间通信和同步-消息队列
- URL中传中文的解决方法
- 如何将oracle表中的字段类型、字段注释说明、字段名一起查询出来
- windows消息码大全