Single sign-on (SSO) implementation solution based on .Net
A few days ago, a friend asked me to help with a single sign-on. In fact, this concept has long been familiar, but there are few practical applications. I have been free recently, so I decided to describe an SSO solution in detail through this article. I hope it will be helpful to everyone. helped. There are many SSO solutions, but the search results are disappointing. Most of them are reposted from each other, and the descriptions are superficial.
Without further ado, let’s get to the point. My idea is to use centralized verification and centralized Passport verification on multiple sites. As shown in the figure below:
#In order to facilitate a clear description, we first define a few nouns. Everything that appears in this article has the following meanings.
Main site: Passport centralized verification server http://www.passport.com/.
Branch: http://www.a.com/, http://www.b.com/, http://www.c.com/
Credential: Data identification generated after the user logs in , used to identify authorized users, can be used in various ways. In the DEMO, I use Cache for the main site and Session for the sub-sites.
Token: A unique identifier issued by Passport that can be circulated in each branch.
OK, now describe the single sign-on process:
Scenario 1. Anonymous user: An anonymous user accesses an authorization page on branch a. First, it jumps to the main site and allows the user to enter their account number and password to log in. After passing the verification, the main site credentials are generated, and the token is generated at the same time, and jumps back to sub-site a. At this time, sub-station a detects that the user already holds the token, so it uses the token to go to the main site again to obtain the user credentials. After successful acquisition, it is allowed The user accesses the authorization page. At the same time, the local credentials of branch a are generated. When the user needs to be authenticated again, the local credentials will be checked first to reduce network interaction.
Scenario 2: A user logged in at sub-site a visits sub-site b: Because the user has logged in at sub-site a and already holds a token, sub-site b will use the token to go to the main site to obtain the user credentials, and the acquisition is successful. Then allow the user to access the authorization page. At the same time, the local credentials of substation b are generated.
After the design is completed, here are some key points for the implementation of the solution:
Token: The token is issued by the main station, and the main station issues the token and generates users at the same time Credentials, and record the correspondence between tokens and user credentials to respond to the corresponding credentials based on the token provided by the user; tokens need to be circulated in various cross-domain sub-stations, so I use the main station’s token in the DEMO Cookie and specify Cookie.Domain="passport.com". How do each branch site share the cookies of the main site? Redirect from the sub-site to the main site page, and then the page reads the cookie and sends it back in the form of URL parameters. You can check the detailed implementation in the DEMO code. Of course, if anyone has a better token implementation, please share it. .
//产生令牌 string tokenValue = Guid.NewGuid().ToString().ToUpper(); HttpCookie tokenCookie = new HttpCookie("Token"); tokenCookie.Values.Add("Value", tokenValue); tokenCookie.Domain = "passport.com"; Response.AppendCookie(tokenCookie);
Main site credential: The main site credential is a relational table that contains three fields: token, credential data, and expiration time. There are many implementation methods to choose from. If reliability is required, use the database. If performance is required, use Cache. In the DEMO, I used the DataTable in Cache. As shown in the following code:
/// <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)); } }
Sub-site credentials: Sub-site credentials are mainly used to reduce network interaction during repeated verification. For example, the user has logged in to sub-site a. When he visits sub-site a again, There is no need to use the token to go to the main site for verification, because branch a already has the user's credentials. The sub-site credentials are relatively simple and can use Session or Cookie.
Base class of sub-site SSO page: The page using SSO in the sub-site will perform a series of logical judgment processing, such as the flow chart at the beginning of the article. If there are multiple pages, it is impossible to write such logic for each page. OK, then encapsulate this set of logic into a base class, and all pages that want to use SSO can inherit this base class. The following code is shown:
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 }
User exit: When the user exits, the main station credentials and the current sub-station credentials are cleared respectively. If site A is required to exit, and sites B and C also exit, you can expand the interface to clear the credentials of each substation.
Clear the expired credentials/tokens of the main site: regularly clear the records whose timeout field in (DataTable) Cache["CERT"] exceeds the current time.
For more articles related to .Net-based single sign-on (SSO) implementation solutions, please pay attention to the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



In C, the char type is used in strings: 1. Store a single character; 2. Use an array to represent a string and end with a null terminator; 3. Operate through a string operation function; 4. Read or output a string from the keyboard.

The usage methods of symbols in C language cover arithmetic, assignment, conditions, logic, bit operators, etc. Arithmetic operators are used for basic mathematical operations, assignment operators are used for assignment and addition, subtraction, multiplication and division assignment, condition operators are used for different operations according to conditions, logical operators are used for logical operations, bit operators are used for bit-level operations, and special constants are used to represent null pointers, end-of-file markers, and non-numeric values.

In C language, special characters are processed through escape sequences, such as: \n represents line breaks. \t means tab character. Use escape sequences or character constants to represent special characters, such as char c = '\n'. Note that the backslash needs to be escaped twice. Different platforms and compilers may have different escape sequences, please consult the documentation.

In C language, the main difference between char and wchar_t is character encoding: char uses ASCII or extends ASCII, wchar_t uses Unicode; char takes up 1-2 bytes, wchar_t takes up 2-4 bytes; char is suitable for English text, wchar_t is suitable for multilingual text; char is widely supported, wchar_t depends on whether the compiler and operating system support Unicode; char is limited in character range, wchar_t has a larger character range, and special functions are used for arithmetic operations.

The difference between multithreading and asynchronous is that multithreading executes multiple threads at the same time, while asynchronously performs operations without blocking the current thread. Multithreading is used for compute-intensive tasks, while asynchronously is used for user interaction. The advantage of multi-threading is to improve computing performance, while the advantage of asynchronous is to not block UI threads. Choosing multithreading or asynchronous depends on the nature of the task: Computation-intensive tasks use multithreading, tasks that interact with external resources and need to keep UI responsiveness use asynchronous.

In C language, char type conversion can be directly converted to another type by: casting: using casting characters. Automatic type conversion: When one type of data can accommodate another type of value, the compiler automatically converts it.

There is no built-in sum function in C language, so it needs to be written by yourself. Sum can be achieved by traversing the array and accumulating elements: Loop version: Sum is calculated using for loop and array length. Pointer version: Use pointers to point to array elements, and efficient summing is achieved through self-increment pointers. Dynamically allocate array version: Dynamically allocate arrays and manage memory yourself, ensuring that allocated memory is freed to prevent memory leaks.

The char array stores character sequences in C language and is declared as char array_name[size]. The access element is passed through the subscript operator, and the element ends with the null terminator '\0', which represents the end point of the string. The C language provides a variety of string manipulation functions, such as strlen(), strcpy(), strcat() and strcmp().
