受欢迎的博客标签

ASP.NET Core Web同一主域名下二级域名web服务单点登录SSO的实现(Cookie方式)

Published

实现登陆认证方式

在同一个一级域名下有很二级域名系统,如:https://www.iaspnetcore.com/, https://search.iaspnetcore.com 等.

但是这些系统都是www.iaspnetcore.com的二级域。

要实现上述功能,首先要了解一个网站有哪些认证登陆方式。Asp .Net Core的认证有很多方式可以实现,如:cookie认证,jwt认证等等。我把它精简一下,从浏览器和服务器之间的认证信息载体的传递的角度,其实只有两种方式可以选择:

1.使用cookie方式实现登陆认证:

浏览器和服务器之间的认证信息传递,用cookie。系统自带的认证方式,最常用的一种。

2.使用token方式实现登陆认证:

如jwt,IdentityServer等,都是基于token在浏览器和服务器如何认证、传递的实现方案。

本次采用cookie方式实现登陆认证。这样的情况就可以在不引用其它框架的情况下,直接基于Cookie实现同域单点登录SSO(Single Sign-on)

使用cookie方式实现登陆认证要实现的功能

实现一个系统登录,其它子系统都登录。一个子系统退出。其它子系统也都退出的功能.

 

同一主域名下二级域名web服务单点登录SSO的实现的条件

要实现上述目的,需要做到以下几点:

1.所有的站点都要使用同一个cookie

2.所有的站点都要使用同一种对cookie的加密、解密方式

3.所有的站点都要使用同一种程序名AplicationName

 

cookie登陆过程
 

在一个Web应用程序中,通常使用一个cookie来表示一个已经登录的用户。

一般的流程是:

1.用户单击登录,进入登录页面。

2.输入有效凭证后(用户名和用户密码),服务器发送给用户浏览器的响应头包含一个带 Set-Cookie 头,其内容为加密信息。

3.被设置上domain 例如 giant.com,每次浏览器向这个domain发送请求时,设置在这个domain上的cookie也会被带上。

options.Cookie.Domain = ".example.com";

should be your cookie domain
the dot . ensure that its a shared cookie in domain

4.在服务器上,cookie将被解密,然后使用解密后的内容来创建用户的 Identity。

 

实现思路

1.发送同一个cookie:浏览器浏览不同的站点时,要让浏览器向web服务站点发送同一个cookie,这个只要把  CookieDomain设置为根域名就可达到让浏览器访问不同子域名时发送同一个cookie。如:CookieDomain=".iaspnetcore.com",

2.所有站点都使用同一种数据解密方式:这个需要把数据保护配置到同一个地方,同一主域名下所有的网站都都使用同一中数据解密方式。如:

services.AddDataProtection()
                    .SetApplicationName("isapnetcore")
                    .PersistKeysToFileSystem(new DirectoryInfo(keysFolder));

 

实现方法

1.修改配置主要统一数据加密方式与统一应用名称
这样其它子域的Cookie加密数据就能识别。

2.配置统一的Cookie名称与写的域名为根域。
这样所有子域都能发现与识别此登录的Cookie信息
3.这样就可以实现一个系统登录,其它子系统都登录
一个子系统退出。其它子系统也都退出的功能

 

添加需要的引用:

path:\Startup.cs

using System.Runtime.InteropServices;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Authentication.Cookies;

 

Startup代码:

添加引用 using Microsoft.AspNetCore.DataProtection,services.AddDataProtection()要用到。添加如下代码:

 public void ConfigureServices(IServiceCollection services)
        {

        

        
            #region 配置数据保护,Preventing Cross-Site Request Forgery (XSRF/CSRF) Attacks in ASP.NET Core
            //https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview?view=aspnetcore-3.1

            var keysFolder = "";

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                keysFolder = "C:\\artifacts";
            else
                keysFolder = "/var/share/ ";

            services.AddDataProtection()
                    .SetApplicationName("isapnetcore")
                    .PersistKeysToFileSystem(new DirectoryInfo(keysFolder));

            #endregion
}
    

 

登录代码

 
        public async void Login()
        {
            if (!HttpContext.User.Identities.Any(identity => identity.IsAuthenticated))
            {
                var user = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "bob") }, CookieAuthenticationDefaults.AuthenticationScheme));
                await HttpContext.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, user);

                HttpContext.Response.ContentType = "text/plain";
                await HttpContext.Response.WriteAsync("Hello First timer");
            }
            else
            {
                HttpContext.Response.ContentType = "text/plain";
                await HttpContext.Response.WriteAsync("Hello old timer");
            }
        }
 
直接上代码,我们需要先封装一个XmlRepository,Key的格式如下:
<?xml version="1.0" encoding="utf-8"?>
<key id="cbb8a41a-9ca4-4a79-a1de-d39c4e307d75" version="1">
  <creationDate>2016-07-23T10:09:49.1888876Z</creationDate>
  <activationDate>2016-07-23T10:09:49.1388521Z</activationDate>
  <expirationDate>2116-10-21T10:09:49.1388521Z</expirationDate>
  <descriptor deserializerType="Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60">
    <descriptor>
      <encryption algorithm="AES_256_CBC" />
      <validation algorithm="HMACSHA256" />
      <masterKey p4:requiresEncryption="true" xmlns:p4="http://schemas.asp.net/2015/03/dataProtection">
        <!-- Warning: the key below is in an unencrypted form. -->
        <value>WYgZNh/3dOKRYJ1OAhVqs56pWPMHei15Uj44DPLWbYUiCpNVEBwqDfYAUq/4jBKYrNoUbaRkGY5o/NZ6a2NTwA==</value>
      </masterKey>
    </descriptor>
  </descriptor>
</key>
 
XmlRepository代码:
public class CustomFileXmlRepository : IXmlRepository
    {
        private readonly string filePath = @"C:\keys\key.xml";

        public virtual IReadOnlyCollection<XElement> GetAllElements()
        {
            return GetAllElementsCore().ToList().AsReadOnly();
        }

        private IEnumerable<XElement> GetAllElementsCore()
        {
            yield return XElement.Load(filePath);
        }
        public virtual void StoreElement(XElement element, string friendlyName)
        {
            if (element == null)
            {
                throw new ArgumentNullException(nameof(element));
            }
            StoreElementCore(element, friendlyName);
        }

        private void StoreElementCore(XElement element, string filename)
        {
        }
    }
 

注意 

C:\keys\key.xml 这个文件路径可以更改,还有就是也可用共享目录或数据库来实现统一管理

到此可以登录试一下。

 
建议阅读: