SSO:Single Sign On 单点登录。SSO是多个应用系统中,用户只需要登录一次,就可以访问所有相互信任的应用系统。
CAS的系统原理图就是这的,上图只是第一次系统进行验证的时候。之后的验证就会清楚很多了。
如果我们要知道CAS是如何在MVC中实现的,我们就要对MVC的框架能够了解,其中,MVC中有两个对象,我觉得是非常需要知道的:
1、Membership对象:验证用户凭据并管理用户设置。
2、FormsAuthentication对象:为 Web 应用程序管理 Forms 身份验证服务。
这样我们就很清楚了,Membership对象,就是我们在CAS Server中的需要验证的信息,它包含了用户的数据库。FormsAuthentication对象,就是帮助我们生成Cookie和ST等的,spring MVC中的架构封装的很好,我们看到不到人家是怎么实现的,但是我们可以知道怎么用它们的就可以了。
我们创建一个MVC的Controller:
<span style="font-size:18px;">namespace MvcApplication1.Controllers { public class AccountController : Controller { // // GET: /Account/LogOn public ActionResult LogOn() { return View(); } // // POST: /Account/LogOn [HttpPost] public ActionResult LogOn(LogOnModel model, string returnUrl) { if (ModelState.IsValid) { if (Membership.ValidateUser(model.UserName, model.Password)) { //中的两个参数第一个为用户的信息,第二个为是否Cookie会持久化 FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe); //存储Cookie信息在本地 HttpCookie cookie = FormsAuthentication.GetAuthCookie(model.UserName, model.RememberMe); cookie.Name = "selfUserInfo"; cookie.Expires = DateTime.Now.AddDays(1); Response.Cookies.Add(cookie); //MVC 封装的,帮助我们进行验证url信息。 if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/") && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\")) { return Redirect(returnUrl); } else { return RedirectToAction("Index", "Home"); } } else { ModelState.AddModelError("", "提供的用户名或密码不正确。"); } } // 如果我们进行到这一步时某个地方出错,则重新显示表单 return View(model); } // FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket( // 1, // 版本号。 // model.UserName, // 与身份验证票关联的用户名。 // DateTime.Now, // Cookie 的发出时间。 // DateTime.Now.AddMinutes(20),// Cookie 的到期日期。 // false, // 如果 Cookie 是持久的,为 true;否则为 false。 // roles ); // 将存储在 Cookie 中的用户定义数据。roles是一个角色字符串数组 // string encryptedTicket = FormsAuthentication.Encrypt(authTicket); //加密 // //存入cookie // HttpCookie authCookie = //new HttpCookie(FormsAuthentication.FormsCookieName, //encryptedTicket); // Response.Cookies.Add(authCookie); // // GET: /Account/LogOff public ActionResult LogOff() { FormsAuthentication.SignOut(); //string subkeyName; //subkeyName = "selfUserInfo"; //HttpCookie aCookie = Request.Cookies["selfUserInfo"]; //aCookie.Values.Remove(subkeyName); //aCookie.Expires = DateTime.Now.AddDays(1); ////Response.Cookies.Add(aCookie); //var memberValidation = HttpContext.Request.Cookies.Get("selfUserInfo"); //从本地的数据库中我们查询到Cookie,然后我们将Cookie进行销毁 if (Request.Cookies["selfUserInfo"] != null) { HttpCookie mycookie; mycookie = Request.Cookies["selfUserInfo"]; Response.Cookies["selfUserInfo"].Expires = System.DateTime.Now.AddMonths(-1); Response.Cookies.Remove("selfUserInfo");//清除 Response.Cookies.Add(mycookie);//写入立即过期的*/ Response.Cookies["selfUserInfo"].Expires = DateTime.Now.AddDays(-1); } var memberValidation = HttpContext.Request.Cookies.Get("selfUserInfo"); return RedirectToAction("Index", "Home"); } // // GET: /Account/Register public ActionResult Register() { return View(); } // // POST: /Account/Register [HttpPost] public ActionResult Register(RegisterModel model) { if (ModelState.IsValid) { // 尝试注册用户 MembershipCreateStatus createStatus; Membership.CreateUser(model.UserName, model.Password, model.Email, null, null, true, null, out createStatus); if (createStatus == MembershipCreateStatus.Success) { //注册新的成员 FormsAuthentication.SetAuthCookie("login", false /* createPersistentCookie */); return RedirectToAction("Index", "Home"); } else { ModelState.AddModelError("", ErrorCodeToString(createStatus)); } } // 如果我们进行到这一步时某个地方出错,则重新显示表单 return View(model); } // // GET: /Account/ChangePassword [MemberValidation] public ActionResult ChangePassword() { return View(); } // // POST: /Account/ChangePassword [MemberValidation] [HttpPost] public ActionResult ChangePassword(ChangePasswordModel model) { if (ModelState.IsValid) { // 在某些出错情况下,ChangePassword 将引发异常, // 而不是返回 false。 bool changePasswordSucceeded; try { MembershipUser currentUser = Membership.GetUser(User.Identity.Name, true /* userIsOnline */); changePasswordSucceeded = currentUser.ChangePassword(model.OldPassword, model.NewPassword); } catch (Exception) { changePasswordSucceeded = false; } if (changePasswordSucceeded) { return RedirectToAction("ChangePasswordSuccess"); } else { ModelState.AddModelError("", "当前密码不正确或新密码无效。"); } } // 如果我们进行到这一步时某个地方出错,则重新显示表单 return View(model); } // // GET: /Account/ChangePasswordSuccess public ActionResult ChangePasswordSuccess() { return View(); } #region Status Codes private static string ErrorCodeToString(MembershipCreateStatus createStatus) { // 请参见 http://go.microsoft.com/fwlink/?LinkID=177550 以查看 // 状态代码的完整列表。 switch (createStatus) { case MembershipCreateStatus.DuplicateUserName: return "用户名已存在。请输入不同的用户名。"; case MembershipCreateStatus.DuplicateEmail: return "该电子邮件地址的用户名已存在。请输入不同的电子邮件地址。"; case MembershipCreateStatus.InvalidPassword: return "提供的密码无效。请输入有效的密码值。"; case MembershipCreateStatus.InvalidEmail: return "提供的电子邮件地址无效。请检查该值并重试。"; case MembershipCreateStatus.InvalidAnswer: return "提供的密码取回答案无效。请检查该值并重试。"; case MembershipCreateStatus.InvalidQuestion: return "提供的密码取回问题无效。请检查该值并重试。"; case MembershipCreateStatus.InvalidUserName: return "提供的用户名无效。请检查该值并重试。"; case MembershipCreateStatus.ProviderError: return "身份验证提供程序返回了错误。请验证您的输入并重试。如果问题仍然存在,请与系统管理员联系。"; case MembershipCreateStatus.UserRejected: return "已取消用户创建请求。请验证您的输入并重试。如果问题仍然存在,请与系统管理员联系。"; default: return "发生未知错误。请验证您的输入并重试。如果问题仍然存在,请与系统管理员联系。"; } } #endregion public ActionResult ValidateCode() { ValidateCodeHelper helper = new ValidateCodeHelper(); string strCode = helper.CreateValidateCode(4); Session["validateCode"] = strCode; var byteData = helper.CreateValidateGraphic(strCode); return File(byteData, "image/jpeg"); } } }</span>
然后我们需要写一个这样的一种特性AuthorizeAttribute:
我们创建一个类集成这个特性就行了:
<span style="font-size:18px;"> public class MemberValidationAttribute : AuthorizeAttribute { public override void OnAuthorization(AuthorizationContext filterContext) { //获取Cookies中的Login //var memberValidation = System.Web.HttpContext.Current.Request.Cookies.Get("login"); //var memberValidation = filterContext.HttpContext.User.Identity.Name; var memberValidation = filterContext.HttpContext.Request.Cookies.Get("selfUserInfo"); //如果memberValidation为null 或者 memberValidation不等于Success if (memberValidation == null) { //页面跳转到 登录页面 filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Account", action = "LogOn" })); return; } //通过验证 return; } }</span>
我们创建一个访问页面HomePage:
<span style="font-size:18px;"> public class HomePageController : Controller { // // GET: /HomePage/ [MemberValidation] public ActionResult HomePage() { return View(); } }</span>
看一下HomePage.cshtml:
<span style="font-size:18px;">@{ ViewBag.Title = "Index"; } <html> <head> <title>HomePage</title> @*<script src="../../Scripts/addPage.js"></script>*@ @*<script src="../../Scripts/EasyuiLayout.js"></script>*@ <link rel="stylesheet" type="text/css" href="../../Content/jquery-easyui-1.3.2/themes/default/easyui.css"> <link rel="stylesheet" type="text/css" href="../../Content/jquery-easyui-1.3.2/themes/icon.css"> <link rel="stylesheet" type="text/css" href="../../Content/jquery-easyui-1.3.2/demo/demo.css"> <script type="text/javascript" src="../../Content/jquery-easyui-1.3.2/jquery-1.8.0.min.js"></script> <script type="text/javascript" src="../../Content/jquery-easyui-1.3.2/jquery.easyui.min.js"></script> <script type="text/javascript" src="../../Content/jquery.balloon.js"></script> <script src="../../Content/jquery-easyui-1.3.2/locale/easyui-lang-zh_CN.js"></script> <link href ="../../CSS/index.css" rel ="stylesheet"/> <script src="../../Scripts/MyScript/ITOO_Common.js"></script> </head> <body> <input type="button" value="权限字典" onclick="addTab('字典表设置', 'http://192.168.24.247:7089/DictionaryType/index?ticket=123')" /> <input type="button" value="新生报到" onclick="addTab('新生报到', 'http://192.168.24.183:8076/FreshStudentReport/FreshStudentReport')" /> <div id="tt" class="easyui-tabs" style="width: 1100px; height: 800px; margin: 0; margin-left: auto; margin-right: auto; border: 1px; overflow: hidden;"> </div> </body> </html> <script> function addTab(tableName, controlerAddress) { $("#tt").tabs('add', { title: tableName, content: '<div style="width:100%;height:99%;">' + '<iframe id="abc" name="PageFrame" frameBorder="0" width="100%" height="100%" src=' + controlerAddress + '>' + '</iframe>' + '</div>', closable: true }); } </script> </span>
spring MVC框架本身是封装的很好的,我们要学会如何去用它,就要清楚里面涉及到的对象。其实,我们先前一直想要实现能够在各个系统中进行验证,没有弄明白一个问题,就是Cookie是存储在本地浏览器中,只有在本地中,我们才可以做各种的判断和验证,否则,就没有办法可以看出该用户是否有权限,或者就是一个用户登陆了之后,所有的用户都可以不需要验证就可以访问所有的系统。