首页 后端开发 C#.Net教程 基于.Net的单点登录(SSO)实现解决方案

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

Dec 28, 2016 pm 04:17 PM
sso单点登录

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

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

为方便清晰描述,先定义几个名词,本文中出现之处均为如下含义。 
主站: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的本地凭证。 

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

设计完成后,接下来是方案实现的一些关键点: 
令牌:令牌由主站颁发,主站颁发令牌同时生成用户凭证,并记录令牌与用户凭证之间的对应关系,以根据用户提供的令牌响应对应的凭证;令牌要在各跨域分站中进行流通,所以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字段超过当前时间的记录。

更多基于.Net的单点登录(SSO)实现解决方案相关文章请关注PHP中文网!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

char在C语言中如何处理特殊字符 char在C语言中如何处理特殊字符 Apr 03, 2025 pm 03:18 PM

C语言中通过转义序列处理特殊字符,如:\n表示换行符。\t表示制表符。使用转义序列或字符常量表示特殊字符,如char c = '\n'。注意,反斜杠需要转义两次。不同平台和编译器可能有不同的转义序列,请查阅文档。

char在C语言字符串中的作用是什么 char在C语言字符串中的作用是什么 Apr 03, 2025 pm 03:15 PM

在 C 语言中,char 类型在字符串中用于:1. 存储单个字符;2. 使用数组表示字符串并以 null 终止符结束;3. 通过字符串操作函数进行操作;4. 从键盘读取或输出字符串。

char与wchar_t在C语言中的区别 char与wchar_t在C语言中的区别 Apr 03, 2025 pm 03:09 PM

在 C 语言中,char 和 wchar_t 的主要区别在于字符编码:char 使用 ASCII 或扩展 ASCII,wchar_t 使用 Unicode;char 占用 1-2 个字节,wchar_t 占用 2-4 个字节;char 适用于英语文本,wchar_t 适用于多语言文本;char 广泛支持,wchar_t 依赖于编译器和操作系统是否支持 Unicode;char 的字符范围受限,wchar_t 的字符范围更大,并使用专门的函数进行算术运算。

C语言各种符号的使用方法 C语言各种符号的使用方法 Apr 03, 2025 pm 04:48 PM

C 语言中符号的使用方法涵盖算术、赋值、条件、逻辑、位运算符等。算术运算符用于基本数学运算,赋值运算符用于赋值和加减乘除赋值,条件运算符用于根据条件执行不同操作,逻辑运算符用于逻辑操作,位运算符用于位级操作,特殊常量用于表示空指针、文件结束标记和非数字值。

c#多线程和异步的区别 c#多线程和异步的区别 Apr 03, 2025 pm 02:57 PM

多线程和异步的区别在于,多线程同时执行多个线程,而异步在不阻塞当前线程的情况下执行操作。多线程用于计算密集型任务,而异步用于用户交互操作。多线程的优势是提高计算性能,异步的优势是不阻塞 UI 线程。选择多线程还是异步取决于任务性质:计算密集型任务使用多线程,与外部资源交互且需要保持 UI 响应的任务使用异步。

char在C语言中如何进行类型转换 char在C语言中如何进行类型转换 Apr 03, 2025 pm 03:21 PM

在 C 语言中,char 类型转换可以通过:强制类型转换:使用强制类型转换符将一种类型的数据直接转换为另一种类型。自动类型转换:当一种类型的数据可以容纳另一种类型的值时,编译器自动进行转换。

C语言 sum 的作用是什么? C语言 sum 的作用是什么? Apr 03, 2025 pm 02:21 PM

C语言中没有内置求和函数,需自行编写。可通过遍历数组并累加元素实现求和:循环版本:使用for循环和数组长度计算求和。指针版本:使用指针指向数组元素,通过自增指针遍历高效求和。动态分配数组版本:动态分配数组并自行管理内存,确保释放已分配内存以防止内存泄漏。

char数组在C语言中如何使用 char数组在C语言中如何使用 Apr 03, 2025 pm 03:24 PM

char 数组在 C 语言中存储字符序列,声明为 char array_name[size]。访问元素通过下标运算符,元素以空终止符 '\0' 结尾,用于表示字符串终点。C 语言提供多种字符串操作函数,如 strlen()、strcpy()、strcat() 和 strcmp()。

See all articles