单点登录、统一认证

随着数字化的不断普及,大型公式或者单位的各个部门逐渐的上了与本身业务相关的各种各样的系统(在这些系统中,以Web系统居多),几乎每个系统都需要识别操作者的身份,并根据其不同的身份,分配一定的权限,做一些操作上的限制。结果很多公司或者部门都在各个系统便各自设计了一套用户资料和权限管理的机制,并提供了用户登录证认。这样满足了上面的需求,但由此带来和用户账号管理不方便,用户资料不统一等等问题。在数字化网络化发展到一定阶段时,对用户资料的整合起来,进行统一的管理变得十分必要。

本文的目的在探讨一个简单有效的方案,将有一定联系,拥有统一用户群的系统进行关联,统一用户的登录资料,并提供统一的登录认证入口。统一认证系统与不同应用子系统之间建立一定的信任关系,通过一定的渠道交换认证信息,在保证用户信息安全的基础上,实现认证关系的共享机制。使用户一个地方一次登录之后,便可以在相应的应用系统群中遨游,而不用没到一个系统就进行登录,甚至使用不同的账号和密码进行登录。

网站与用户之间的认证关系,我们一般通过Session来建立,而Session(一般)在不同网站中是不能共享的。本方案的难点在于统一认证系统和应用子系统之间认证信息的共享。用户在统一认证系统中登录之后,与统一登录系统建立了认证关系,如果用户转向应用子系统,此时如何与子系统建立认证关系,如何将统一认证系统的认证关系迁移复制到子系统,这将是我们要解决的问题。


ASP.NET的Session保存机制(会话状态模式)有三种......


ASP.NET 支持三种会话状态模式: 

InProc:In-Proc 模式将值存储在 ASP.NET 辅助进程的内存中。因此,该模式提供了对这些值的最快访问。但是,当 ASP.NET 辅助进程被回收时,状态数据便会丢失。 

StateServer:与上一模式不同,StateServer 模式使用独立的 Microsoft Windows 服务来存储会话变量。因为该服务独立于 Microsoft Internet Information Server (IIS),所以它可以在另一独立的服务器上运行。您可以将此模式用于负载平衡解决方案,因为多个 Web 服务器可共享会话变量。尽管在重新启动 IIS 时会话变量不会丢失,但在跨越进程边界时,性能会受到影响。 

SqlServer:如果会话信息的持久性对于您很重要,那么您可以使用 SqlServer 模式,以便利用 Microsoft SQL Server 来确保达到最高级别的可靠性。SqlServer 模式类似于进程外模式,只是前者的会话数据维护在 SQL Server 中。SqlServer 模式还让您能够利用位于 IIS 进程外的一个状态存储区,该状态存储区既可位于本地计算机上,也可位于远程服务器上。

网站的默认Session状态模式应该是InProc,限制了本系统网站使用。StateServer和SqlServer都作为扩展,将会话信息存储在IIS进程之外,实现了不同Web服务器之间的共享。当然,这两种模式都需要做相应的配置和消耗一定的性能,我们暂且不说这一点。仔细研究发现,这两种扩展模式主要面向的是网站的分流和负载均衡,共享Session的网站之间的结合是非常非常密切的,并且ASP.NET将所有的实现都进行了封装,我们无法获取和记录每一次共享的细节。这并不适合我们最开始的需求。

假设:A系统通过Session保存了一个User实例,那么如果B系统需要使用这个Session,则必需拥有A系统中User的细节。如果A、B两个系统是完全不同,甚至其中不同细节User类,更甚至A、B系统中都不只一处功能使用到Session,Session的命名又总碰巧一致。呵呵,那一切将变得不可思议。当然,如果我A、B为统一个系统的两个不同的应用层,那StateServer和SqlServer这两种方式将能够很好的满足需求。至于要满足我们上面的需求,只能是另外想办法了。

寻找解决办法,我们比较关系用户体验,那么先从用户的使用流程开始.......

根据我们的需求,用户的体验一般有两种:

一、对于使用多个子系统的用户,将有可能直接登录统一认证系统,并通过统一系统的子系统连接列表,跳转到多个子系统;二、对于一些使用单个子系统,或者自为单具体事情进入我们平台,或者是登录超时了,这是他应该向直接进入特定子系统,那么我们需要将登录验证在他进入子系统之前插入。两种不同方式的三个系统之间的交互过程如下图所示:

单点登录、统一认证_第1张图片

图 1. 一般步骤,同时登录多个子系统

单点登录、统一认证_第2张图片

图 2. 直接进入子系统,子系统之间跳转

我将按照第一种交互方式进行解释:

1、用户先与统一登录系统进行交互,使用唯一的帐号密码进行登录,此时不涉及任何子系统;

2、用户登录成功后,统一登录系统将信任的应用子系统列表呈现给用户;

3、用户根据需要,选择子系统连接访问子系统,用户与子系统的交互开始;

4、由于用户与子系统此时还没有建立认证关系,所以子系统将用户重定向到统一登录系统;

5、统一登录系统验证用户的登录信息,发现用户已经登录,便将登录信息插入到数据库,再将验证信息发给用户,即返回一个等待页面;

6、用户将等待页面中的验证信息提交(自动)到子系统,子系统获取认证信息;

7、子系统通过一定的办法和等待页面中的验证信息进行验证,并与用户建立了信任关系;

与ASP.NET封装的实现方案项目,这交互过程看起来十分烦碎,我们还需要自己实现大量的功能。但我们的交互实现过程都是可控的,各个系统之间传递的信息内容,什么时候传递,我能都可以限制和约定,并且能够将每一次系统之间的交互记录都进行登记,这才是我们需要的。至于烦碎,其实对用户来说,增加的步骤就是出现自动提交的等待登录页面,如果两个系统都能正常运行,网络也没有出现堵塞,用户等待的时间将及其短暂,甚至没能看到页面。并且我们能够对等待页面做一定的美化,使用户就算看到等待页面,也不会感到厌烦。

说了这么多,统一认证系统的应用子系统Session的共享还没有开始,这是本方案最大的难点......

下面就简述统一认证系统的应用子系统Session的共享的实现,我和一位同事根据大伙的讨论结果,分两种方式进行实现,详细情况如下:

第一种方式:通过MD5加密随机字符串,使用了Web服务实现了子系统和统一认证系统之间的交互验证。验证信息包含两部分用户在统一登录系统的Session ID和数据库中的随机ID。当子系统将用户重定向到统一登录系统的时候,验证的交互过程开始,详细步骤如下:

1、统一登录系统获取用户的Session ID和登录名

2、统一登录系统将Session ID和登录名插入到数据库,产生一个随机的数据库ID

3、将Session ID和数据库ID结合起来,进行MD5加密

4、使用MD5密文和数据库ID构建一个登录等待页面,返回给用户

5、用户将登录等待页面中的信息自动提交给子系统

6、子系统通过Web服务将MD5密文和数据库ID提交回统一登录系统

7、统一登录系统查询数据库,并进行验证

8、统一登录系统返回用户登录名,并删除数据库中的登录记录。

9、子系统与用户建立认证关系

单点登录、统一认证_第3张图片

图 3. MD5随机加密,Web服务实现验证

第二种方式:通过对认证信息(登录令牌)进行非对称加密,一次交互实现验证。验证信息为一个包含了产生时间的Token类。验证的交互过程同样是在重定向到统一登录系统的时候开始,详细步骤如下:

1、构建一个包含生成时间的Token类,将Token类序列化

2、使用SHA-1,对序列化Token编码进行散列,产生验证码H

3、将序列化Token编码和验证码H结合,使用公钥加密

4、使用密文构建一个登录等待页面,返回给用户

5、用户将登录等待页面中的信息自动提交给子系统

6、子系统使用私钥进行解密

7、子系统分离出散列验证码H和序列化Token编码,并进行SHA-1验证

8、检查Token中的生成时间,判断是否超时

9、子系统与用户建立认证关系

单点登录、统一认证_第4张图片

图 4. 非对称加密,一次交互实现验证两种方式各有优缺点,大家很明显就能看出,我就不做总结。我们最终选择的方案是第一种,并且在验证过程中增加了一个Session识别子系统,防止非法的阻塞和冒充。即在应用子系统将用户重定向到统一认证系统系统时,子系统与用户建立Session,并在用户转交认证信息时,验证是否原本用户。防止有非法者获取了和用户转交的认证信息,并在用户之前提交给子系统,骗取认证。

你可能感兴趣的:(ASP.NET)