基于的单点登录实现方案 Net
几天前,一个朋友让我帮忙单点登录。其实这个概念已经很熟悉了,但实际应用却很少,所以最近难得放松一下。所以我决定通过这篇文章详细描述一个SSO解决方案,希望对大家有所帮助。SSO的解决方案有很多,但搜索结果却令人失望。大部分都是互相转载,描述也只是走马观花。我们少说话,言归正传。我的想法是使用集中认证,多个站点会进行集中的Passport认证。如下图所示:
为了便于清晰描述,先定义几个名词,本文中所有出现的名词都有以下含义。主站:护照集中认证服务器http://www.passport.com/.分站:http://www.a.com/, http://www.b.com/, http://www.c.com/证书:用户登录后生成的数据标识符,用于识别授权用户,可以多种方式使用。在演示中,主站使用缓存,而子站使用会话。令牌:由Passport颁发的唯一标识符,可以在每个子站中流通。好了,现在描述一下单点登录的过程:场景1。匿名用户:匿名用户访问A分站上的一个授权页面,首先跳转到主站,要求用户输入账号和密码登录。验证后生成主站证书,同时生成一个令牌,跳回到子站A,此时子站A检测到用户已经持有令牌,于是再次使用令牌去主站获取用户证书,获取成功后允许用户访问授权页面。同时生成变电站A的本地证书。当用户需要再次验证时,将首先检查本地证书,以减少网络交互。场景二:在变电站a登录的用户访问变电站b:由于用户已经在变电站a登录并已经持有令牌,变电站b将使用令牌去主站获取用户凭证,获取成功后,允许用户访问授权页面。同时生成变电站b的本地证书。
设计完成后,方案的实现有几个关键点:令牌:令牌由主站发放,主站发放令牌的同时生成用户凭证,并记录令牌与用户凭证的对应关系,以便根据用户提供的令牌响应相应的凭证;令牌要在各种跨域分站中流通,所以我在DEMO中使用主站的cookies进行令牌,并指定cookies。domain=' passport.com '。各分站如何共享主站的Cookie?从分站重定向到主站页面,然后从这个页面读取Cookie并以URL参数的形式返回。您可以在DEMO代码中查看详细的实现,当然,如果有人有更好的令牌实现,也可以分享。复制代码如下: //生成令牌字符串令牌值=guid。newguid()。tostring()。toupper();httpookie令牌Cookie=新的httpookie('令牌');令牌Cookie。值。添加('值',令牌值);令牌Cookie。Domain=' passport.com回应。AppendCookie(令牌cookie);主证书:主证书是一个关系表,包含三个字段:令牌、证书数据和过期时间。有很多方法可以选择。如果需要可靠性,请使用数据库;如果需要性能,请使用缓存。在演示中,我使用了缓存中的数据表。代码如下所示:复制代码如下: ///summary ///Initialize数据结构/////备注/////-。信息(用户凭据)|超时(过期时间)|///| | -。{ if (HttpContext。当前缓存[' CERT ']==null){ DataTable dt=new DataTable();dt。列。添加('令牌',类型。GetType('System。字符串');dt。列['标记']。唯一=真;dt。列。添加('信息',类型。GetType('System。object ');dt。列['信息']。DefaultValue=nulldt。列。添加(“超时”),类型。GetType('System。DateTime ');dt。列['超时']。默认值=日期时间。现在。加分钟(双倍。解析(系统。configuration . configuration manager . appsettings[' time out ']);DataColumn[]键=新的DataColumn[1];keys[0]=dt。列[' token '];dt。PrimaryKey=keys//Cache的过期时间是token过期时间* 2 httpcontext . current . Cache . insert(' cert ',dt,null,datetime.maxvalue,timespan . from minutes . double . parse(system。configuration . configuration manager . app settings[' time out '])* 2));}}分站券:分站券主要用于减少重复认证时的网络交互。例如,用户已经在子站A登录,当他再次访问子站A时,他不需要使用令牌去主站进行认证,因为子站A已经有了用户的凭证。分站券比较简单,可以使用Session和Cookie。变电站SSO页面基类:使用SSO的变电站页面会做一系列的逻辑判断处理,比如文章开头的流程图。如果有多个页面,不可能为每个页面都写这样的逻辑,OK,那就把这个逻辑打包成一个基类,任何想用SSO的页面都可以继承这个基类。
如下代码所示:复制代码代码如下:使用系统;使用系统。数据;使用系统。配置;使用系统网络.使用系统。网络安全;使用系统网络。用户界面使用系统。网络控件;使用系统。网页组件;使用系统网络。UI。HtmlControls使用系统。文本。正则表达式;命名空间单点登录.Class { ///summary ///授权页面基类////总结公共类AuthBase :系统.网络。用户界面。第{页受保护的覆盖void OnLoad(event args e){ if(Session[' Token ']!=null) { //分站凭证存在回应。写('恭喜,分站凭证存在,您被授权访问该页面!');} else { //令牌验证结果如果(请求QueryString['Token']!=空){如果(请求.QueryString['Token']!='$Token$') { //持有令牌字符串标记值=请求查询字符串[' Token '];//调用WebService获取主站凭证单点登录.SiteA。参考护照。令牌服务令牌服务=新的单点登录SiteA。refpassport。令牌服务();对象o=令牌服务. TokenGetCredence(令牌值);如果(o!=null) { //令牌正确会话['令牌]=o;回应。写('恭喜,令牌存在,您被授权访问该页面!');} else { //令牌错误回应。重定向(这个。替换令牌());} } else { //未持有令牌回应。重定向(这个。替换令牌());} } //未进行令牌验证,去主站验证否则{回应.重定向(这个。gettokenurl());} }基础on LoAd(e);} ///摘要///获取带令牌请求的网址/在当前统一资源定位器中附加上令牌请求参数////summary ///returns/returns私有字符串gettokenurl(){字符串URL=Request .Url。绝对的新Regex(@'^.*\?=.$');if (reg .IsMatch(URL))URL=' Token=$ Token $ ';else url='?Token=$ Token $ ';返回'http://www.passport.com/gettoken.aspx?服务器网址编码(网址);} ///摘要///去掉统一资源定位器中的令牌///在当前统一资源定位器中去掉令牌参数////摘要////返回/返回私有字符串替换令牌(){字符串网址=请求.Url。AbsoluteUriurl=Regex .替换(网址,@'(\?|)令牌=。*、“、”正则表达式.忽略大小写);返回'http://www.passport.com/userlogin.aspx?服务器网址编码(网址);} }//结束类}用户退出:用户退出时分别清空主站凭证与当前分站凭证。如果要求A站点退出,乙,丙站点也退出,可自行扩展接口清空每个分站凭证。主站过期凭证/令牌清除:定时清除(数据表)缓存["CERT"]中超时字段超过当前时间的记录。
版权声明:基于的单点登录实现方案 Net是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。

















