cas原理.doc_第1页
cas原理.doc_第2页
cas原理.doc_第3页
cas原理.doc_第4页
cas原理.doc_第5页
已阅读5页,还剩14页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

基本原理首先,在我们修改之间,先了解以下CAS运行基本原理。CAS服务器,客户端(应用),浏览器的序列图如下:其中:ST:Service Ticket,用于客户端应用持有,每个ST对应一个用户在一个客户端上TGT:Ticket Granting Ticket,存储在CAS服务器端和用户cookie两个地方CAS服务器持有ST与TGT+客户端的映射关系,客户端持有ST与用户Session的映射关系,在renew的情况下,每次客户端根据用户 Session将ST发送给CAS服务器端,服务器端检验ST是否存在即可知道此用户是否已登陆。在普通情况下,用户第一次登陆应用时,客户端将用户页面 重定向到CAS服务器,服务器取出用户cookie中的TGT,检验是否在服务器中存在,若存在则生成ST返回给客户端 (若不存在则要求登陆,登陆成功后同样返回ST给客户端),客户端拿到ST后再发送给CAS服务器认证是否为真实ST,认证成功即表示登陆成功我们可以看到,其实我们需要做的就是第2步中返回的登陆页面由服务器改放到客户端,然后让第3步中由用户在客户端上输入用户名密码但提交到CAS服务器端,登陆成功与失败都将转向客户端。服务器详细登陆流程对于上一节讲述的整体登陆流程,CAS 3.3.1服务器端上是依赖于Spring Webflow 1.0.3实现的,其主要流程在/WEB-INF/login-webflow.xml中配置,配置的页面流活动图如下(有删节):图中命名均按照webflow配置文件中的命名,图解如下:Action State图标表示webflow配置文件中的action-state或view-state节点Decision图标表示webflow配置文件中的decision-state节点Initial State图标表示webflow配置文件中的start-state节点Final State图标表示webflow配置文件中的end-state节点登陆的流程依照图上说明,在此不再累述,下面简单说明下CAS服务器端Spring Webflow的运作首先CAS在/WEB-INF/web.xml中配置命名为cas的servlet以拦截输入请求,若不在casservlet mapping范围内的资源路径请求均转向到/login上: cas org.jasig.cas.web.init.SafeDispatcherServlet publishContext false 1 cas /login.所有映射到cas servlet上的请求都将经过/WEB-INF/cas-servlet.xml检查确定进入哪个Action,cas-servlet.xml中最重要的两个bean就是handlerMappingB和handlerMappingChandlerMappingB配置了登陆流程进入的路径映射,而handlerMappingC则配置了其他的流程的路径映射。/WEB-INF/login-webflow.xml流程配置文件即是在handlerMappingB中通过/login映射进入的。Webflow依据一个生成的flowExecutionKey来确定一个流程实例走到了哪一步,每次页面流程运转总是需要提交这个 flowExecutionKey来告诉webflow它是从流程的哪个位置出发的有了以上理论作为依据,我们在下一节就可以根据自己的需要修改流程,使 之支持远程登录了服务器登陆流程修改目标修改后的登陆流程活动图如下:图中橙色为我们修改的流程节点,这里我们增加了一个开始节点remoteLogin和一个结束节点remoteCallbackView,删除了原有的loginFormView节点、 viewGenericLoginSuccess以及renew节点(renew节点由于系统无此需求而删除),然后将所有这些节点的转向全部都转向到remoteCallbackView节点,因为登陆和显示登陆成功信息都应该是客户端完成的服务器端实现目标好了,原理到这里已经啰嗦完了,下一节讲如何着手修改CAS服务器端啦。修改需要基于几个基本原则:不影响原有统一登陆界面功能客户端应尽量保持简单尽量保证原有功能的完整性和安全性对于第三点,必须事先说明:将登陆页面放到客户端本身就是降低了CAS安全性,这意味着作为服务向外发布的CAS服务器中的用户密码有可能由于客户端的不安全性而导致泄露,整个CAS系统成为了一个“水桶形态”,整个CAS体系的安全性将取决于所有客户端中安全性最低的一个。这也是CAS官方一直不推荐的方式。服务器端修改接下来我们讲解服务器端修改的详细过程:首先,修改/WEB-INF/web.xml,为cas增加一个/remoteLogin的映射: cas /remoteLogin然后修改cas-servlet.xml文件,增加我们对/remoteLogin映射的处理,需要增加一个新流程: loginController remoteController 然后在cas-servlet.xml文件中添加我们上面所配置的remoteController的bean: 可以看到上面将请求指向了webflow配置文件/WEB-INF/remoteLogin-webflow.xml文件,我们需要创建此文件并配置其成为我们所需的流程,以下是remoteLogin-webflow.xml全文: 以上文件根据原login-webflow.xml文件修改,黄色背景为修改部分。可以看到,我们在流程中增加了remoteLogin Action节点和remoteCallback View节点,下面我们配置remoteLogin节点:在/WEB-INF/cas-servlet.xml文件中增加remoteLoginAction配置:同时创建com.baidu.cas.web.flow.RemoteLoginAction类:/* 远程登陆票据提供Action.* 根据InitialFlowSetupAction修改.* 由于InitialFlowSetupAction为final类,因此只能将代码复制过来再进行修改.* * author GuoLin*/public class RemoteLoginAction extends AbstractAction /* CookieGenerator for the Warnings. */ NotNull private CookieRetrievingCookieGenerator warnCookieGenerator; /* CookieGenerator for the TicketGrantingTickets. */ NotNull private CookieRetrievingCookieGenerator ticketGrantingTicketCookieGenerator; /* Extractors for finding the service. */ NotEmpty private List argumentExtractors; /* Boolean to note whether weve set the values on the generators or not. */ private boolean pathPopulated = false; protected Event doExecute(final RequestContext context) throws Exception final HttpServletRequest request = WebUtils.getHttpServletRequest(context); if (!this.pathPopulated) final String contextPath = context.getExternalContext().getContextPath(); final String cookiePath = StringUtils.hasText(contextPath) ? contextPath :/; (Setting path for cookies to: + cookiePath); this.warnCookieGenerator.setCookiePath(cookiePath); this.ticketGrantingTicketCookieGenerator.setCookiePath(cookiePath); this.pathPopulated = true; context.getFlowScope().put(ticketGrantingTicketId, this.ticketGrantingTicketCookieGenerator.retrieveCookieValue(request); context.getFlowScope().put(warnCookieValue, Boolean.valueOf(this.warnCookieGenerator.retrieveCookieValue(request); final Service service = WebUtils.getService(this.argumentExtractors, context); if (service != null & logger.isDebugEnabled() logger.debug(Placing service in FlowScope: + service.getId(); context.getFlowScope().put(service, service); / 客户端必须传递loginUrl参数过来,否则无法确定登陆目标页面 if (StringUtils.hasText(request.getParameter(loginUrl) context.getFlowScope().put(remoteLoginUrl,request.getParameter(loginUrl); else request.setAttribute(remoteLoginMessage, loginUrl parameter must besupported.); return error(); / 若参数包含submit则进行提交,否则进行验证 if (StringUtils.hasText(request.getParameter(submit) return result(submit); else return result(checkTicketGrantingTicket); public void setTicketGrantingTicketCookieGenerator( final CookieRetrievingCookieGenerator ticketGrantingTicketCookieGenerator) this.ticketGrantingTicketCookieGenerator = ticketGrantingTicketCookieGenerator; public void setWarnCookieGenerator(final CookieRetrievingCookieGeneratorwarnCookieGenerator) this.warnCookieGenerator = warnCookieGenerator; public void setArgumentExtractors( final List argumentExtractors) this.argumentExtractors = argumentExtractors; 以上黄色背景为修改部分,要求客户端必须传入loginUrl参数,且当客户端传入submit参数时,直接为其提交用户名密码然后再配置remoteCallbackView显示节点,修改src/default_perties文件,增加remoteCallbackView配置:# 配置远程回调页面remoteCallbackView.(class)=org.springframework.web.servlet.view.JstlViewremoteCallbackView.url=/WEB-INF/view/jsp/default/ui/remoteCallbackView.jsp创建/WEB-INF/view/jsp/default/ui/remoteCallbackView.jsp文件: var remoteUrl = $remoteLoginUrl?validated=true; / 构造错误消息 var errorMessage = ; errorMessage = &errorMessage= + encodeURIComponent(); / 构造service var serivce = ; service = &service= + encodeURIComponent($service); / 跳转回去 window.location.href = remoteUrl + errorMessage + service; $remoteLoginMessage以上文件注意黄色背景部分validated=true,这里我们与客户端约定,当客户端登陆页面后带有参数validated=true时,不进行票据认证请求。这是因为,客户端登陆页面为http:/clienthost/login.jsp,那么当用户访问URL http:/clienthost/login.jsp时, 客户端会重定向到CAS中央服务器请求TGT认证,但认证失败后CAS中央认证服务器会重定向到客户端登陆页面并显示登陆框,此时客户端必须以某种规则避 免重新请求中央认证服务器认证, 在这里我们与客户端约定,当回发的请求为登陆页面且带有参数validated=true时即不转发TGT认证请求,即 http:/clienthost/login.jsp?validated=true 请求客户端不会重新发送TGT认证请求给中央认证服务器到此,服务器端修改完成,下一篇介绍客户端如何构建客户端实现目标客户端实现主要需要满足5个case:1. 用户未在中央认证服务器登陆,访问客户端受保护资源时,客户端重定向到中央认证服务器请求TGT认证,认证失败,转回客户端登陆页面,保证受保护资源URL信息不丢失2. 用户未在中央认证服务器登陆,访问客户端登陆页面时,客户端重定向到中央认证服务器请求TGT认证,认证失败,转回客户端登陆页面,此次登录页面不再受保护,允许访问3. 用户已在中央认证服务器登陆,访问客户端受保护资源时,客户端重定向到中央认证服务器请求TGT认证,认证成功,直接转回受保护资源4. 用户在客户端登陆页面提交用户名密码,客户端将用户名密码信息提交给服务器端,认证失败,转回客户端登陆页面,携带失败信息并保证转到登陆页面前受保护资源URL信息不丢失5. 用户在客户端登陆页面提交用户名密码,客户端将用户名密码信息提交给服务器端,认证成功,转回转到登陆页面前受保护资源对于case 1和case 3,普通的CAS客户端即可满足需求,但对于case 4和case 5,则需要我们定制自己的登陆页面。对于case 2,主要是需要满足部分登陆页面希望在用户未登陆状态显示登陆框,在已登陆状态显示用户欢迎信息的需求,实现这个需求我们是通过让CAS客户端认证器满足 一个排除约定,即当用户请求路径为登陆页面且带有validated=true的参数时,即不进行重定向TGT认证请求客户端修改方案远程客户端修改,对于任何一种客户端方案都可以实现,这里为了简单起见,我们给出的修改方案基于CAS官方提供的Java客户端3.1.3。首先我们使用CAS Client 3.1.3搭建一个CAS客户端,具体搭建方法可以参考CAS官网:CAS Client for Java 3.1根据服务器流程修改方案,我们可以知道,所有的远程请求都必须携带有loginUrl参数信息以使得服务器端知道在认证失败后转向客户端登陆页面。 而在CAS客户端上,上一节的case 4和case 5,我们主要通过提交表单的方式传递loginUrl,而case 1, case 3则是依靠org.jasig.cas.client.authentication.AuthenticationFilter类进行的转向,但使用 AuthenticationFilter转向时,是没有loginUrl信息的,因此我们首先需要重新实现一个自己的认证过滤器,以下是我们自己的认证 过滤器的代码:/* 远程认证过滤器.* 由于AuthenticationFilter的doFilter方法被声明为final,* 只好重新实现一个认证过滤器,支持localLoginUrl设置.* * author GuoLin* */public class RemoteAuthenticationFilter extends AbstractCasFilter public static final String CONST_CAS_GATEWAY = _const_cas_gateway_; /* * 本地登陆页面URL. */ private String localLoginUrl; /* * The URL to the CAS Server login. */ private String casServerLoginUrl; /* * Whether to send the renew request or not. */ private boolean renew = false; /* * Whether to send the gateway request or not. */ private boolean gateway = false; protected void initInternal(final FilterConfig filterConfig) throws ServletException super.initInternal(filterConfig); setCasServerLoginUrl(getPropertyFromInitParams(filterConfig, casServerLoginUrl, null); log.trace(Loaded CasServerLoginUrl parameter: + this.casServerLoginUrl); setLocalLoginUrl(getPropertyFromInitParams(filterConfig, localLoginUrl, null); log.trace(Loaded LocalLoginUrl parameter: + this.localLoginUrl); setRenew(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, renew, false); log.trace(Loaded renew parameter: + this.renew); setGateway(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, gateway, false); log.trace(Loaded gateway parameter: + this.gateway); public void init() super.init(); CommonUtils.assertNotNull(this.localLoginUrl, localLoginUrl cannot be null.); CommonUtils.assertNotNull(this.casServerLoginUrl, casServerLoginUrl cannot be null.); 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 String ticket = request.getParameter(getArtifactParameterName(); final Assertion assertion = session != null ? (Assertion) session .getAttribute(CONST_CAS_ASSERTION) : null; final boolean wasGatewayed = session != null & session.getAttribute(CONST_CAS_GATEWAY) != null; / 如果访问路径为localLoginUrl且带有validated参数则跳过 URL url = new URL(localLoginUrl); final boolean isValidatedLocalLoginUrl = request.getRequestURI().endsWith(url.getPath() & CommonUtils.isNotBlank(request.getParameter(validated); if (!isValidatedLocalLoginUrl & CommonUtils.isBlank(ticket) & assertion = null & !wasGatewayed) log.debug(no ticket and no assertion found); if (this.gateway) log.debug(setting gateway attribute in session); request.getSession(true).setAttribute(CONST_CAS_GATEWAY, yes); final String serviceUrl = constructServiceUrl(request, response); if (log.isDebugEnabled() log.debug(Constructed service url: + serviceUrl); String urlToRedirectTo = CommonUtils.constructRedirectUrl( this.casServerLoginUrl, getServiceParameterName(), ser

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论