标签:
参考文档:
http://www.360doc.com/content/14/0719/16/834950_395508432.shtml
http://blog.sina.com.cn/s/blog_7d491cfb0101fa5o.html
前两篇都是参考以下两篇文章:
http://denger.iteye.com/blog/809170
http://denger.iteye.com/blog/1119233
一.前言
cas版本:cas-server-3.5.2-release
以下我们所做的服务器端代码的修改都是在cas-server-webapp中
二.问题分析
获取cas登录时所需要的参数,其中最主要是lt和execution这两个动态生成的参数,因此,实现cas自定义登录的步骤:
第一步:获取lt/execution的值
第二步:自定义界面进行登录
第三步:给出相应的提示信息,并跳转到指定界面
三.实现过程
1、修改服务器端代码,包括创建ProvideLoginTicketAction.class,用于处理获得it/execution的值,并修改login-webflow等配置文件等操作
(1)创建ProvideLoginTicketAction.class
package org.jasig.cas.util; import javax.servlet.http.HttpServletRequest; import javax.validation.constraints.NotNull; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jasig.cas.web.support.WebUtils; import org.springframework.webflow.action.AbstractAction; import org.springframework.webflow.execution.Event; import org.springframework.webflow.execution.RequestContext; public class ProvideLoginTicketAction extends AbstractAction { private static final String PREFIX = "LT"; private final Log logger = LogFactory.getLog(getClass()); @NotNull private UniqueTicketIdGenerator ticketIdGenerator; public final String generate(final RequestContext context){ final String loginTicket = this.ticketIdGenerator.getNewTicketId(PREFIX); WebUtils.putLoginTicket(context, loginTicket); return "generated"; } public void setTicketIdGenerator(final UniqueTicketIdGenerator generator){ this.ticketIdGenerator = generator; } @Override protected Event doExecute(RequestContext context) throws Exception { final HttpServletRequest request = WebUtils.getHttpServletRequest(context); if(request.getParameter("get-lt") != null && request.getParameter("get-lt").equalsIgnoreCase("true")){ final String loginTicket = this.ticketIdGenerator.getNewTicketId(PREFIX); WebUtils.putLoginTicket(context, loginTicket); return result("loginTicketRequested"); } return result("continue"); } }
(2)创建AjaxLoginServiceTicketAction.class
package org.jasig.cas.util; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.StringUtils; import org.jasig.cas.authentication.principal.Service; import org.jasig.cas.web.support.WebUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.webflow.action.AbstractAction; import org.springframework.webflow.execution.Event; import org.springframework.webflow.execution.RequestContext; public class AjaxLoginServiceTicketAction extends AbstractAction { private final Logger log = LoggerFactory.getLogger(getClass()); protected static final String J_CALLBACK = "feedBackUrlCallBack"; @Override protected Event doExecute(final RequestContext context) { HttpServletRequest request = WebUtils.getHttpServletRequest(context); Event event = context.getCurrentEvent(); boolean isAjax = BooleanUtils.toBoolean(request.getParameter("isajax")); if (!isAjax){ // 非 ajax/iframe 方式登录,返回当前 event. return event; } boolean isLoginSuccess; // Login Successful. if ("success".equals(event.getId())){ //是否登录成功 final Service service = WebUtils.getService(context); final String serviceTicket = WebUtils.getServiceTicketFromRequestScope(context); if (service != null){ //设置登录成功之后 跳转的地址 request.setAttribute("service", service.getId()); } request.setAttribute("ticket", serviceTicket); isLoginSuccess = true; } else { // Login Fails.. isLoginSuccess = false; } boolean isFrame = BooleanUtils.toBoolean(request.getParameter("isframe")); String callback = request.getParameter("callback"); String clientUrl = request.getParameter("login-at"); if(StringUtils.isEmpty(callback)){ // 如果未转入 callback 参数,则采用默认 callback 函数名 callback = J_CALLBACK; } if(isFrame){ // 如果采用了 iframe ,则 concat 其 parent 。 callback = "parent.".concat(callback); } request.setAttribute("isFrame", isFrame); request.setAttribute("callback", callback); request.setAttribute("clientUrl", clientUrl); request.setAttribute("isLogin", isLoginSuccess); return new Event(this, "ajaxView"); // 转入 ajaxLogin.jsp 页面 } }
(3)在cas-server.xml中声明ProvideLoginTicketAction和AjaxLoginServiceTicketAction
<bean id="provideLoginTicketAction" class="org.jasig.cas.util.ProvideLoginTicketAction" p:ticketIdGenerator-ref = "loginTicketUniqueIdGenerator"></bean> <bean id="ajaxLoginServiceTicketAction" class="org.jasig.cas.util.AjaxLoginServiceTicketAction"/>
(4)修改login-webflow.xml
<action-state id="generateServiceTicket"> <evaluate expression="generateServiceTicketAction" /> <!-- <transition on="success" to ="warn" /> <transition on="error" to="generateLoginTicket" />--> <transition on="success" to ="loginResponse" /> <transition on="error" to="loginResponse" /> <transition on="gateway" to="gatewayServicesManagementCheck" /> </action-state>
<action-state id="realSubmit"> <evaluate expression="authenticationViaFormAction.submit(flowRequestContext, flowScope.credentials, messageContext)" /> <transition on="warn" to="warn" /> <transition on="success" to="sendTicketGrantingTicket" /> <!--将 to="viewLoginForm" 修改为 to="loginResponse" --> <transition on="error" to="loginResponse" /> </action-state>
(5)在login-webflow.xml中添加
<action-state id="loginResponse"> <evaluate expression="ajaxLoginServiceTicketAction" /> <!--非ajax/iframe方式登录,采取原流程处理 --> <transition on="success" to="warn" /> <transition on="error" to="viewLoginForm" /> <!-- 反之,则进入 viewAjaxLoginView 页面 --> <transition on="ajaxView" to="viewAjaxLoginView" /> </action-state>
在<on-start></on-start>标签后添加
<action-state id="provideLoginTicketAction"> <evaluate expression="provideLoginTicketAction"/> <transition on="loginTicketRequested" to="viewResponseLoginTicketInfo"/> <transition on="continue" to="ticketGrantingTicketExistsCheck" /> </action-state> <view-state id="viewResponseLoginTicketInfo" view="responseLoginTicketInfoView" model="credentials"> <binder> <binding property="username" /> <binding property="password" /> </binder> <on-entry> <set name="viewScope.commandName" value="‘credentials‘" /> </on-entry> <transition on="submit" bind="true" validate="true" to="realSubmit"> <evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" /> </transition> </view-state>
在最后一个<end-state>标签后添加
<end-state id="viewAjaxLoginView" view="viewAjaxLoginView" />
(6)创建ProvideLoginTicketAction执行后要跳转的responseLoginTicketInfo.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <% response.addHeader("Content-Type", "application/x-javascript"); out.print("flightHandler({‘lt‘:‘");%>${loginTicket}<%out.print("‘,‘execution‘:‘");%>${flowExecutionKey}<%out.print("‘});");%>
(7)创建AjaxLoginServiceTicketAction执行后要跳转的ajaxLogin.jsp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <script type="text/javascript"> <% Boolean isFrame = (Boolean)request.getAttribute("isFrame"); Boolean isLogin = (Boolean)request.getAttribute("isLogin"); // 登录成功 if(isLogin){ if(isFrame){%> parent.location.replace(‘${service}?ticket=${ticket}‘) <%} else{%> location.replace(‘${service}?ticket=${ticket}‘) <%} }else{ %> parent.location.replace(‘${clientUrl}?msg=error‘) <% } %> </script>
(8)在default_views.properties(路径:/cas-server-webapp/src/main/webapp/WEB-INF/classes/default_views.properties)
中增加responseLoginTicketInfo.jsp和ajaxLogin.jsp的配置
responseLoginTicketInfoView.(class)=org.springframework.web.servlet.view.JstlView
responseLoginTicketInfoView.url=/WEB-INF/view/jsp/default/ui/responseLoginTicketInfo.jsp
viewAjaxLoginView.(class)=org.springframework.web.servlet.view.JstlView
viewAjaxLoginView.url=/WEB-INF/view/jsp/default/ui/ajaxLogin.jsp
2、创建客户端代码
(1)客户端登录界面index.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="index.aspx.cs" Inherits="login" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>Client demo</title> </head> <body> <div></div> <form action="" method="post" onsubmit="return loginValidate();" target="ssoLoginFrame" id="loginFrm"> <div class="red" style="height:12px;color:red" id="login_msg"></div> <ul> <li> <em>用户名:</em> <input name="username" id="username" type="text" class="required" style="width: 180px" size="25"/> </li> <li> <em>密码:</em> <input name="password" type="password" id="password" class="required" style="width: 180px" size="25"/> </li> <li class="mai"> <em> </em> <input type="checkbox" name="rememberMe" id="rememberMe" value="true"/> 自动登录 <a href="/retrieve">忘记密码?</a> </li> <li> <em> </em> <input type="hidden" name="isajax" value="true" /> <input type="hidden" name="isframe" value="true" /> <input type="hidden" name="lt" value="" id="cas_loginTicket"/> <input type="hidden" name="execution" value="" id="cas_execution"/> <input type="hidden" name="_eventId" value="submit"/> <input class="btn-submit" name="submit" accesskey="l" value="登录" tabindex="4" type="submit"/> <input class="btn-reset" name="reset" accesskey="c" value="重置" tabindex="5" type="reset"/> <input type="hidden" name="login-at" value ="" id="login_at"/> </li> </ul> </form> </body> <script type = "text/javascript" src="js/jquery-1.9.1.min.js"></script> <script type = "text/javascript" src="js/index.js"></script> <iframe style="display:none;width:0;height:0" id="ssoLoginFrame" name="ssoLoginFrame" src="javascript:false;"></iframe> </html>
(2)对应的js代码index.js
var urlData; $(function () { initData(); var login_error_msg = GetQueryString("msg"); if (login_error_msg != null && login_error_msg.toString().length > 1) { $("#login_msg").text("用户名或密码错误"); } // $("#login_msg").text(login_error_msg.toString()); }); var flushLoginTicket = function () { var _service = ‘service=‘ + encodeURIComponent(urlData._service); var urlOfGetLt = urlData.serverUrl + ‘?‘ + _service + ‘&get-lt=true&n=‘ + new Date().getTime(); $.ajax({ type: ‘get‘, async: false, url: urlOfGetLt, dataType: ‘jsonp‘, jsonp: ‘callback‘, jsonpCallback: ‘flightHandler‘, success: function (data) { $("#cas_loginTicket").val(data.lt); $("#cas_execution").val(data.execution); }, error: function () { console.log("ERROR") } }); } var loginValidate = function () { var msg; if ($.trim($(‘#username‘).val()).length == 0) { msg = "用户名不能为空。"; } else if ($.trim($(‘#password‘).val()).length == 0) { msg = "密码不能为空。"; } if (msg && msg.length > 0) { $(‘#login_msg‘).fadeOut().text(msg).fadeIn(); return false; // Can‘t request the login ticket. } else if ($(‘#cas_loginTicket‘).val().length == 0) { $(‘#login_msg‘).text(‘服务器正忙,请稍后再试..‘); return false; } else { return true; } } function GetQueryString(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); var r = window.location.search.substr(1).match(reg); if (r != null) return unescape(r[2]); return null; } function initData() { $.get(‘conf/url.json‘).done(function (data) { urlData = eval(‘(‘ + data + ‘)‘); $("#loginFrm")[0].setAttribute("action", urlData.serverUrl); $("#login_at").val(urlData.clientUrl); flushLoginTicket(); }); }
(3)对应的json数据url.json,用于存储服务器url和客户端url
/* _service:成功后跳转的路径 serverUrl:要连接的服务器路径 clientUrl:登录失败后跳转的路径 */ { "_service": "http://localhost:54872/demoweb/home.aspx", "serverUrl": "https://localhost:8443/cas/login", "clientUrl": "http://localhost:54872/demoweb/index.aspx" }
以上只是将整个修改过程提炼出来,并没有解释详细原因,具体细节可参考上面的几篇文章。
标签:
原文地址:http://www.cnblogs.com/hzwl-2015/p/4613185.html