单点登录通用类

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单点登录通用类相关的知识,希望对你有一定的参考价值。

说明

自从上次的《偷懒小工具 - Excel导出》发布以后,看阅读量还可以,就决定继续分享一下其他方面的帮助类。

风格还是类似的极简风,登录方法,调用的代码尽量超过三行,然后搞定一切。源代码参考文章最下方。


同域和跨域

a.baidu.com 中。a 是二级域名,baidu 是一级域名。同样的一级域名是可以共享Cookie的。

不同一级域名,因为同源策略原因,不能共享Cookie。也就是跨域

例如:微信扫码登录,就是这种跨域的实用例子

a.baidu.com 和 b.baidu.com 是可以共享cookie,也就是同域。

www.baidu.com 和 www.qq.com 就属于跨域。

单点登录

SSO 单点登录,主要就是使用统一的身份验证模块,然后各网站共享身份验证。

也就是只登录一次,其他网站均可免登陆。

关于身份验证方面,各位如有疑惑可自行百度。或者看一下,我记录的 《ASP.NET身份认证》

(是给自己看的可能有些乱)

因为同源策略的问题,所以同域和跨域方法实现差距比较大。

我这边根据同域和跨域,这两种不同情况,分享两个帮助类。

这两个帮助类,互相独立。各位按照自己的需求选择查看使用。

(因为就一个人精力有限,白天还要上班,没有进行太多测试)设计不合理或者BUG,肯定会有一些。

流程图

首先,看一下同域的流程图。

技术分享

 

再看一下,跨域的流程图

技术分享

看着,很简单吧。我相信你们肯定可以看懂,我就不作解释了。下面看使用。

使用步骤

配置

这里WebConfig,采用了如下的配置。

技术分享WebConfig

用户认证网站,直接使用~/Login.aspx 指向自己的登录页面。

其他网站,使用 “认证网站地址”+?link+“本网站地址”。这种方式,来进行登录后的跳转。

同域

共同一级域名的情况。可以使用SSOGeneralSameDomain类,进行登录。

  1. 首先,需要你自行制作一个登录界面,自行进行用户名和密码的验证
  2. 调用如下方法。
技术分享MVC登录

其中,Login就是用户登录方法。一共两行代码。name 参数是你需要保存的数据。

其中,Index方法,可以获得你保存的用户名。(这里为了方便使用的明文用户名)

技术分享WebForm登录

WebForm登录方式是一样的,这里不做过多描述。

调用 SSOGeneralSameDomain.LogUp(); 可进行用户注销。

此时你的网站,就可以共享身份验证了。

跨域

不同一级域名的情况。可以使用SSOGeneralCrossDomain类,进行登录

  1. 首先,需要自行制作一个登录界面。这个没法省略,或者你直接用我示例代码的登录。
  2. 认证网站,调用LogIn方法。其他网站,调用LogInClient方法。
技术分享认证网站登录

需要传递:保存的数据、Cookie名称、保存时长

技术分享其他网站登录

需要传递:认证网站地址、Cookie名称、保存时长

此时,你就可以完成跨域单点登录了。但是注意,认证网站,还需要调用一个验证方法。

技术分享验证方法

思路和过程

同域 

分析

同域的思路比较简单,也相对来说比较好实现。有两点要考虑的(如果有其他办法,请留言

  1. Request 和 Response 的操作问题
  2. 其他网站的登录后跳转问题

Request 操作:因为Mvc和WebForm的Request,存在于两个不同的类(HttpContextBase和Page)。

  这个找了半天,也没有想到能公用的办法,于是就用抽象工厂来搞了一下。

跳转问题:因为Forms身份认证的ReturnUrl参数,只能拿到文件,而不能拿到网址。所以没法跳转到对应网站。

  这个我在博问上试着问了一下,结果有一个大哥说:你要这么多干啥,没啥用。当时我就懵逼了!!!

     后来,没有找到什么好办法,就用的笨办法,也就是使用link进行跳转。

做法

这两个问题解决了,我们接下来看看代码。还是向上次一样,一步一步来说一下。

做Request和Response操作封装

首先,创建一个抽象类,然后把需要的方法封装一下,接着定义Page和HttpContext两个子类,继承实现

技术分享Operation
技术分享OperationHttpContext
技术分享OperationPage

做同域单点登录的类

1. 首先,分析一下每个登录,都需要名字和过期时间,那么这俩字段上移。 肯定都得有登录方法,那么方法上移。

技术分享SSOGeneral

这里字段Set 私有,也是安全性的考虑。我在初始化的时候,就传递这两个参数。 

2. 接着,创建 SSOGeneralSameDomain 类,继承抽象类。

定义私有字段,Operation用来执行操作。构造函数中对这个字段进行赋值。

技术分享构造函数

实现抽象类的LogIn方法。这个方法只有三步:1.创建Forms认证票据。2.保存到Cookie中。3.成功后跳转。

技术分享Login
技术分享Create

CreateTicket 和 CreateCookie 方法逻辑非常简单,我就不说明了。说一下跳转逻辑。 

技术分享RedirectPage

有link 找link,没有找ReturnUrl,再没有直接跳转到根目录。 至此登录做完了。

3. 最后,做注销和获取内容方法。这边为了方便,使用静态类实现的。

注销都是固定的方法,获取内容,就是拿Cookies。然后解密

技术分享Static

同域的帮助类,至此就算完成了。

跨域

跨域真的是比较纠结的一点,因为我懒,所以一般都是先上网找相关文章。

发现,文章有用的非常少。一些伪跨域的特别多,有些卡卡卡说一大堆,结果发现不同的是二级域名。

还有就是使用 接口,来回传信息的。因为我想做帮助类,用接口的话就耦合在一起了。不太想用。

PS:找了一天,最后烦躁了不找了,开始自己想自己研究。

分析

实际上同域需要处理的地方,就是传递凭证。接收到凭证以后,就会进行本地存储,所以传递是终点。

跨域需要考虑的点,就比较多了,除了同域的问题还有以下几点:(如果有其他办法,请留言

  1. Cookie不能共享,如何验证信息
  2. 如何处理登录用户的持久化
  3. 登录和认证要用什么形式展现

Cookie不能共享:使用Token作为凭据传递,可根据Token获取保存信息。

持久化:提供持久化接口,任何方式只要满足此接口即可。我这里提供了Http缓存和Cookies方法。

登录和认证:流程跟上面的图差不多。主要开放五个方法:

LogIn(登录)、LogInClient(其他网站登录)、ValidationToken(认证)、GetUserData(获取登录内容)、LogUp(注销)

做法

1. 首先,还是跟同域一样做Operation 然后Page 和 HttpContextBase继承这个Operation

技术分享Operation
技术分享OperationPage
技术分享OperationHttpContext

2. 因为会有凭证的传递,所以我们还需要一个加密。这里,我给出一个接口,并给出了DES加密的实现方法。

  各位可以按照自己想进行的加密逻辑,自行扩展。

技术分享IOperationSecret
技术分享OperationSecret

3. 持久层也是必不可少的,用来存放已经登录的用户信息。这里也是给出的接口。并给出了Cookie 和 Cache的操作方法

  各位可以按照自己想实现的持久层,进行处理。

技术分享IOperationToken
技术分享OperationCookies

CreateToken 生成凭证的这个方法。我这边采用最简单的GUID进行生成的,这种无规律的是没有办法伪造的。

SetToken的UserData,使用的就是上方的加密认证。

我觉得只要涉及到HTTP传递,就肯定能拦截,所以重点应该是怎么不让他破解。加密算法,各位可以自行实现。

技术分享OperationCache
public class SSOToken
    {
        public string UserData { get; set; }
        public string Token { get; set; }
        public DateTime OverdueTime { get; set; }
    }

持久层存储模型,就使用这个必不可少的几个字段进行存储。

4. 跨域单点登录类,因为这个类比较复杂,所以我不想提太多公共方法或字段。

技术分享SSOGeneral

创建SSOGeneralCrossDomain类,我们把参数都作为属性提出来,然后把接口也进行提取。

技术分享构造函数

我们看一下LogIn 登录方法是如何实现的。

技术分享LogIn

这个方法,是认证中心点击保存以后执行的方法。

先进行SetToken 把登录信息存到持久层。然后返回对应的Token。

接着进行GetRedirectUrl。这个方法获取我们登录成功后,将要跳转的地址。

技术分享GetRedirectUrl

接下来的,跟同域的情况一样。这里就不多说了。我们现在已经实现了,认证中心的登录。接下来,我们制作其他网站的登录。

其他网站,使用此功能,也要定义自己的Login.aspx页面,只是在这个页面调用这个方法。

技术分享LogInClient

我们先判断,是登录还是认证。比如:我们没有登录,打开网站A,这种情况就是登录。网站A登录后,跳转到网站B,这种情况就是认证

技术分享IsLogin

接下来我们验证Token,这一步很重要。这一步可以把网站引导到认证中心,或者自动认证。

技术分享ValidationToken
  1. 首先,我们认为没有传递凭证 就是需要登录。UserData 是已经认证完毕的内容。
  2. 我们判断是否同域,因为Cookie只有在一个域下才可以调用。
  3. 我们把当前的地址信息封装,引导到认证中心进行认证。
  4. 没有进行验证的都会在这一步卡住。

接下来,就是显而易见的 解密、本地存储了。很简单不多讲了。

GetUserData 和 LogUp。一个是获取本地Cookie,一个是注销登录(跟同域操作一样)

至此,我们的单点登录,全部搞定。接下来,我们进行测试。

测试

同域

首先,我们创建两个认证中心。一个MVC的,一个WebForm的。然后Web创建2个网站,MVC创建1个。用来做跳转。

技术分享

Authorize 认证中心,使用的是MVP 的PV模式。首先我们给Web相关的网站,定义统一的Web.Config

技术分享WebConfig

同域情况下,Web1\\2 登录地址均指向 Authorize

接下来,在登录后调用方法

技术分享Login

我们在 Web1 里面写一下获取方法 和 注销

技术分享Web1

这个时候,我们Web1设为启动项。然后就可以测试了。具体页面,我就不粘贴了。可以参考下方源码

跨域

跨域需要在各个应用底下,创建自己的Login.aspx登录页面。然后调用这个方法,或者你创建主页调用一样。

Web1网站 调用方法如下

技术分享Login

加载内容如下

技术分享Page_Load

Authorize网站,调用方法如下

技术分享认证网站

在Initialize 初始化的时候,添加验证方法。这样可以接受其他网站发送的验证请求。

在登录页面,直接调用登录方法即可。

具体测试项目,都在Github上。各位可以自行下载。 

源码地址:https://github.com/chenxygx/SSOGeneral

以上是关于单点登录通用类的主要内容,如果未能解决你的问题,请参考以下文章

偷懒小工具 - 通用单点登录类(可跨域)

SSO单点登录

sso单点登录实现

029. SSO单点登录的通用架构实现

分享吧基于通用业务平台与CAS的单点登录服务的研究

求解!单点登录怎么实现的?