SSO英文全称Single Sign On(单点登陆)。SSO是在多个应用系统中,用户只须要登陆一次就能够访问全部相互信任的应用系统。它包括能够将此次主要的登陆映射到其余应用中用于同一个用户的登陆的机制。它是目前比较流行的企业业务整合的解决方案之一。(本段内容来自百度百科)html
今天这篇文章将介绍SSO的一种实现方式,代码超简单,仅用来验证个人思路是否可行,具体细节请你们来完善!跨域
什么是二级域名呢?例如:服务器
对于二级域名的单点登陆,咱们能够很是方便的经过共享cookie来实现,简单的说,就是在设置Form票据的时候,将cookie的domain设置为顶级域名便可,例如:cookie
HttpCookie cookie = new HttpCookie(FormsAuthCookieName, encryptedTicket); cookie.Expires = rememberMe ? expirationDate : DateTime.MinValue; cookie.HttpOnly = true; cookie.Path = "/"; cookie.Domain = "domain.com"; context.Response.Cookies.Set(cookie);
这种方式不涉及跨域,当cookie的domain属性设置为顶级域名以后,全部的二级域名均可以访问到身份验证的cookie,在服务器端只要验证了这个cookie就能够实现身份的验证。asp.net
可是,当跨域的时候,例如:dom
这个时候就不能共享cookie了,因此上面的解决方案就会失效。那么,要实现跨域的单点登陆该如何作呢?请继续往下看。this
关于跨域的SSO的设计思路,我画了一个简单的流程图:url
首先,我将跨域的SSO分为SSO-Server和SSO-Client两个部分,SSO-Client能够是多个的。.net
SSO-Server主要负责用户登陆、注销、为SSO-Client分配taken、验证taken的工做。设计
登陆和注销采用的是Form认证方式,不少地方都有详细的介绍,我以前也写过一篇文章,想了解的能够去看看:asp.net Forms身份验证详解
为SSO-Client分配Token的部分,在SSO-Client请求SSO受信页面的时候,检查SSO-Server是否登陆,若是没有登陆则跳转到SSO-Server的登陆页面,若是已登陆,则执行分配Token的代码,在分配完成之后将TokenID做为参数添加到returnUrl中,并跳转到returnUrl,具体的分配代码以下:
if (Domain.Security.SmartAuthenticate.LoginUser != null) { //生成Token,并持久化Token Domain.SSO.Entity.SSOToken token = new Entity.SSOToken(); token.User = new Entity.SSOUser(); token.User.UserName = Domain.Security.SmartAuthenticate.LoginUser.UserName; token.LoginID = Session.SessionID; Domain.SSO.Entity.SSOToken.SSOTokenList.Add(token); //拼接返回的url,参数中带Token string spliter = returnUrl.Contains('?') ? "&" : "?"; returnUrl = returnUrl + spliter + "token=" + token.ID; Response.Redirect(returnUrl); }
当完成Token分配以后,页面将带有TokenID的参数跳转到SSO-Client页面,并在SSO-Client的Cookie中添加Token值,在之后的每次请求中,SSO-Client经过调用SSO-Server的服务来验证Token的合法性。
我是经过WebService来验证Token的。
首先在SSO-Server定义一个Web Service:
[WebMethod] public Entity.SSOToken ValidateToken(string tokenID) { if (!KeepToken(tokenID)) return null; var token = Domain.SSO.Entity.SSOToken.SSOTokenList.Find(m => m.ID == tokenID); return token; } [WebMethod] public bool KeepToken(string tokenID) { var token = Domain.SSO.Entity.SSOToken.SSOTokenList.Find(m => m.ID == tokenID); if (token == null) return false; if (token.IsTimeOut()) return false; token.AuthTime = DateTime.Now; return true; }
ValidateToken用来验证TokenID的合法性,KeepToken用来保持Token不会过时。
SSO-Client经过调用Validate验证Token,并获得当前的登陆用户信息。接下来看看SSO-Client的实现。
SSO-Client做为受信系统来存在的,它本身没有认证系统,只能经过SSO-Server来完成用户身份认证的工做。
当用户请求SSO-Client的受保护资源时,SSO-Client会首先是否有TokenID,若是存在TokenID,则调用SSO-Server的WebService来验证这个TokenID是否合法;
验证成功之后将会返回SSOToken的实例,里面包含已登陆的用户信息。具体代码以下:
if (!string.IsNullOrEmpty(tokenID)) { AuthTokenService.AuthTokenServiceSoapClient client = new AuthTokenService.AuthTokenServiceSoapClient(); var token = client.ValidateToken(tokenID); if (token != null) { this.lblMessage.Text = "登陆成功,登陆用户:" + token.User.UserName + "<a href='http://sso-server.com/logout.aspx?returnUrl=" + Server.UrlEncode("http://sso-client.com") + "'>退出</a>"; } else { Response.Redirect("http://sso-server.com/sso.aspx?returnUrl=" + Server.UrlEncode("http://sso-client.com/default.aspx")); } } else { Response.Redirect("http://sso-server.com/sso.aspx?returnUrl=" + Server.UrlEncode("http://sso-client.com/default.aspx")); }
文章中已经介绍了个人具体思路和一些实现,若是你仍然感兴趣,能够下载个人代码>>Demo.SSO
源代码的部署:
1. 在IIS中建立两个站点,分别绑定到SSO-Server和SSO-Client,它们绑定的域名分别是sso-server.com和sso-client.com
2. 在hosts文件中添加两行映射,将sso-server.com和sso-client.com映射到127.0.0.1,确保能够访问
3.访问sso-client.com,这个时候页面将跳转到sso-server.com的登陆页面,用户名、密码随便输入,而后点击登陆便可
我很认真的完成了这个方案,也感谢你很认真的看完!欢迎拍砖!