前些天一位朋友要我帮忙做一单点登录,其实这个概念早已耳熟能详,但实际应用很少,难得最近轻闲,于是决定通过本文来详细描述一个SSO解决方案,希望对大家有所帮助。SSO的解决方案很多,但搜索结果令人大失所望,大部分是相互转载,并且描述的也是走马观花。

闲话少叙,进入正题,我的想法是使用集中验证方式,多个站点集中Passport验证。 如下图所示:

为方便清晰描述,先定义几个名词,本文中出现之处均为如下含义。

主站:Passport集中验证服务器 http://www.passport.com/ 。

分站http://www.a.com/http://www.b.com/http://www.c.com/

凭证:用户登录后产生的数据标识,用于识别授权用户,可为多种方式,DEMO中主站我使用的是Cache,分站使用Session。

令牌:由Passport颁发可在各分站中流通的唯一标识。

OK,现在描述一下单点登录的过程:

情形一、匿名用户:匿名用户访问分站a上的一个授权页面,首先跳转到主站让用户输入帐号、密码进行登录,验证通过后产生主站凭证,同时产生令牌,跳转回分站a,此时分站a检测到用户已持有令牌,于是用令牌再次去主站获取用户凭证,获取成功后允许用户访问该授权页面。同时产生分站a的本地凭证,当该用户需要再次验证时将先检查本地凭证,以减少网络交互。

情形二、在分站a登录的用户访问分站b:因为用户在分站a登录过,已持有令牌,所以分站b会用令牌去主站获取用户凭证,获取成功后允许用户访问授权页面。同时产生分站b的本地凭证。

设计完成后,接下来是方案实现的一些关键点:

令牌:令牌由主站颁发,主站颁发令牌同时生成用户凭证,并记录令牌与用户凭证之间的对应关系,以根据用户提供的令牌响应对应的凭证;令牌要在各跨域分站中进行流通,所以DEMO中令牌我使用主站的Cookie,并指定Cookie.Domain="passport.com"。各分站如何共享主站的Cookie?从分站Redirect到主站页面,然后该页面读取Cookie并以URL参数方式回传即可,可在DEMO代码中查看详细实现,当然如果哪位有更好的令牌实现方式也拿出来分享。


//产生令牌
string tokenValue = Guid.NewGuid().ToString().ToUpper();
HttpCookie tokenCookie = new HttpCookie("Token");
tokenCookie.Values.Add("Value", tokenValue);
tokenCookie.Domain = "passport.com";
Response.AppendCookie(tokenCookie); 

主站凭证:主站凭证是一个关系表,包含了三个字段:令牌、凭证数据、过期时间。有多种实现方式可供选择,要求可靠的话用数据库,要求性能的话用Cache,DEMO中我使用的是Cache中的DataTable。如下代码所示:


/// <summary>
/// 初始化数据结构
/// </summary>
/// <remarks>
/// ----------------------------------------------------
/// | token(令牌) | info(用户凭证) | timeout(过期时间) |
/// |--------------------------------------------------|
/// </remarks>
private static void cacheInit()
{
    if (HttpContext.Current.Cache["CERT"] == null)
    {
        DataTable dt = new DataTable();

        dt.Columns.Add("token", Type.GetType("System.String"));
        dt.Columns["token"].Unique = true;

        dt.Columns.Add("info", Type.GetType("System.Object"));
        dt.Columns["info"].DefaultValue = null;

        dt.Columns.Add("timeout", Type.GetType("System.DateTime"));
        dt.Columns["timeout"].DefaultValue = DateTime.Now.AddMinutes(double.Parse(System.Configuration.ConfigurationManager.AppSettings["timeout"]));

        DataColumn[] keys = new DataColumn[1];
        keys[0] = dt.Columns["token"];
        dt.PrimaryKey = keys;

        //Cache的过期时间为 令牌过期时间*2
        HttpContext.Current.Cache.Insert("CERT", dt, null, DateTime.MaxValue, TimeSpan.FromMinutes(double.Parse(System.Configuration.ConfigurationManager.AppSettings["timeout"]) * 2));
    }
}

分站凭证:分站凭证主要用于减少重复验证时网络的交互,比如用户已在分站a上登录过,当他再次访问分站a时,就不必使用令牌去主站验证了,因为分站a已有该用户的凭证。分站凭证相对比较简单,使用Session、Cookie均可。

分站SSO页面基类:分站使用SSO的页面会做一系列的逻辑判断处理,如文章开头的流程图。如果有多个页面的话不可能为每个页写一个这样的逻辑,OK,那么把这套逻辑封装成一个基类,凡是要使用SSO的页面继承该基类即可。如下代码所示:


using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Text.RegularExpressions;

namespace SSO.SiteA.Class
{
    /// <summary>
    /// 授权页面基类
    /// </summary>
    public class AuthBase : System.Web.UI.Page
    {
        protected override void OnLoad(EventArgs e)
        {
            if (Session["Token"] != null)
            {
                //分站凭证存在
                Response.Write("恭喜,分站凭证存在,您被授权访问该页面!");
            }
            else
            {
                //令牌验证结果
                if (Request.QueryString["Token"] != null)
                {
                    if (Request.QueryString["Token"] != "$Token$")
                    {
                        //持有令牌
                        string tokenValue = Request.QueryString["Token"];
                        //调用WebService获取主站凭证
                        SSO.SiteA.RefPassport.TokenService tokenService = new SSO.SiteA.RefPassport.TokenService();
                        object o = tokenService.TokenGetCredence(tokenValue);
                        if (o != null)
                        {
                            //令牌正确
                            Session["Token"] = o;
                            Response.Write("恭喜,令牌存在,您被授权访问该页面!");
                        }
                        else
                        {
                            //令牌错误
                            Response.Redirect(this.replaceToken());
                        }
                    }
                    else
                    {
                        //未持有令牌
                        Response.Redirect(this.replaceToken());
                    }
                }
                //未进行令牌验证,去主站验证
                else
                {
                    Response.Redirect(this.getTokenURL());
                }
            }

            base.OnLoad(e);
        }

        /// <summary>
        /// 获取带令牌请求的URL
        /// 在当前URL中附加上令牌请求参数
        /// </summary>
        /// <returns></returns>
        private string getTokenURL()
        {
            string url = Request.Url.AbsoluteUri;
            Regex reg = new Regex(@"^.*\?.+=.+$");
            if (reg.IsMatch(url))
                url += "&Token=$Token$";
            else
                url += "?Token=$Token$";

            return "http://www.passport.com/gettoken.aspx?BackURL=" + Server.UrlEncode(url);
        }

        /// <summary>
        /// 去掉URL中的令牌
        /// 在当前URL中去掉令牌参数
        /// </summary>
        /// <returns></returns>
        private string replaceToken()
        {
            string url = Request.Url.AbsoluteUri;
            url = Regex.Replace(url, @"(\?|&)Token=.*", "", RegexOptions.IgnoreCase);
            return "http://www.passport.com/userlogin.aspx?BackURL=" + Server.UrlEncode(url);
        }

    }//end class
}

用户退出:用户退出时分别清空主站凭证与当前分站凭证。如果要求A站点退出,B、C站点也退出,可自行扩展接口清空每个分站凭证。

主站过期凭证/令牌清除:定时清除(DataTable)Cache[“CERT”]中timeout字段超过当前时间的记录。

点击此处下载DEMO

1.在IIS中配置站点

配置4个站点指向相应的目录,并分别指定4个站点的主机头:

http://www.passport.com/

http://www.a.com/

http://www.b.com/

http://www.c.com/

2.修改hosts文件以将域名解析到本地站点

127.0.0.1          http://www.passport.com/

127.0.0.1          http://www.a.com/

127.0.0.1          http://www.b.com/

127.0.0.1          http://www.c.com/

转自:http://www.cnblogs.com/zgx/archive/2009/07/31/1536059.html

asp.net单点登录(SSO)解决方案的更多相关文章

  1. 基于.Net的单点登录(SSO)解决方案

    前些天一位朋友要我帮忙做一单点登录,其实这个概念早已耳熟能详,但实际应用很少,难得最近轻闲,于是决定通过本文来详细描述一个SSO解决方案,希望对大家有所帮助.SSO的解决方案很多,但搜索结果令人大失所 ...

  2. Atitit. 单点登录sso 的解决方案 总结

    Atitit.  单点登录sso 的解决方案 总结 1. 系统应用场景and SSO模式选型 2 2. 系统应用的原则与要求 2 2.1. 开发快速简单::绝大部分系统来说,开发快速简单为主 2 2. ...

  3. Asp.Net Core基于Cookie实现同域单点登录(SSO)

    在同一个域名下有很多子系统 如:a.giant.com  b.giant.com   c.giant.com等 但是这些系统都是giant.com这个子域. 这样的情况就可以在不引用其它框架的情况下, ...

  4. 十六、【适合中小企业的.Net轻量级开源框架】EnterpriseFrameWork框架核心类库之单点登录SSO

    回<[开源]EnterpriseFrameWork框架系列文章索引> EFW框架源代码下载:http://pan.baidu.com/s/1qWJjo3U 单点登录(Single Sign ...

  5. Redis缓存实现单点登录SSO

    .NET基于Redis缓存实现单点登录SSO的解决方案 .NET基于Redis缓存实现单点登录SSO的解决方案   一.基本概念 最近公司的多个业务系统要统一整合使用同一个登录,这就是我们耳熟能详的单 ...

  6. 单点登录SSO:概述与示例

    目录 概述 演示一:零改造实施单点登录 演示二: 单点注销 演示三:集成AD认证 演示四:客户端单点登录 演示五:移动端单点登录 单点登录SSO概述 本系列将由浅入深的,带大家掌握最新单点登录SSO方 ...

  7. 单点登录SSO的实现原理 (转)

    单点登录SSO(Single Sign On)说得简单点就是在一个多系统共存的环境下,用户在一处登录后,就不用在其他系统中登录,也就是用户的一次登录能得到其他所有系统的信任.单点登录在大型网站里使用得 ...

  8. 单点登录(一)-----理论-----单点登录SSO的介绍和CAS+选型

    什么是单点登录(SSO) 单点登录主要用于多系统集成,即在多个系统中,用户只需要到一个中央服务器登录一次即可访问这些系统中的任何一个,无须多次登录. 单点登录(Single Sign On),简称为 ...

  9. [转载]单点登录SSO:概述与示例

    原文地址: https://www.cnblogs.com/baibaomen/p/sso.html 目录 概述 演示一:零改造实施单点登录 演示二: 单点注销 演示三:集成AD认证 演示四:客户端单 ...

随机推荐

  1. JMS - 基本概念

    连接工厂创建连接对象的工厂. 连接客户端与 JMS 服务器之间建立的连接.创建一个或多个会话. 会话创建消息.生产者和消费者,会话是 消息由三部分组成:消息头.消息属性和消息体. 生产者创建和发送消息 ...

  2. Nginx - Additional Modules, About Your Visitors

    The following set of modules provides extra functionality that will help you find out more informati ...

  3. SQL Server的三种物理连接之Loop Join(一)

    Sql Server有三种物理连接Loop Join,Merge Join,Hash Join, 当表之间连接的时候会选择其中之一,不同的连接产生的性能不同,理解这三种物理连接对性能调优有很大帮助. ...

  4. IMDb Search

    主要是一个搜索电影,显示电影信息的小程序,开发坏境是xcode7.0,swift2.0 创建HTTP请求连接并对连接格式化 了解NSURLSession类的使用方法 通过NSURLSession类的d ...

  5. CSS的兼容性解决方案

    什么是兼容性? 同一个网页,在不同浏览器下(IE6.IE7.IE8)下的显示效果不一致,这就是说"CSS不兼容". IETESTer可以同时测试IE5.5.IE6.IE7.IE8这 ...

  6. C++记录2

    1, 求成员变量的偏移: 2, const实现机制:在编译期间完成,对于内置类型,如int, 编译器可能使用常数直接替换掉对此变量的引用.而对于结构体不一定. 编译器在优化代码时把j直接优化成64h了 ...

  7. 取消定时-CICS

    CICE CA R 做定时的时候最好加上REqID

  8. HTML5+J2EE实现文件异步上传

    P.S. HTML5经过了W3C的8年努力,终于正式推广了.这次升级最大的就是升级了XMLHTTPRequest,让它变成了XMLHTTPRequest Level II(这有啥奇怪的?).这个对象现 ...

  9. 【转】JavaScript中undefined与null的区别

    通常情况下, 当我们试图访问某个不存在的或者没有赋值的变量时,就会得到一个undefined值.Javascript会自动将声明是没有进行初始化的变量设为undifined. 如果一个变量根本不存在会 ...

  10. 译文:Javascript-function's return

    个人理解+google翻译.如有错误,请指正.原文来自MDN:return 概要 由function返回指定值. 版本信息 实现: JavaScript 1.0, NES 2.0(NES:游戏机在欧洲 ...