.net core实践系列之SSO-同域实现(一)

简介: .net core实践系列之SSO-同域实现(一)

前言

SSO的系列还是以.Net Core作为实践例子与大家分享,SSO在Web方面复杂度分同域与跨域。本篇先分享同域的设计与实现,跨域将在下篇与大家分享。


如有需要调试demo的,可把SSO项目部署为域名http://sso.cg.com/,Web1项目部署为http://web1.cg.com,http://web2.cg.com,可以减少配置修改量


源码地址:https://github.com/SkyChenSky/Core.SSO


效果图


488722-20181011194445430-285491216.gif


SSO简介


单点登录,全称为Single Sign On,在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。


它是一个解决方案,目的是为了整合企业内多个应用系统,仅由一组账号只需进行一次登录,就可被授权访问多个应用系统。


image.png


流程描述


未登录状态访问业务Web应用会引导到认证中心。


用户在认证中心输入账号信息通过登录后,认证中心会根据用户信息生成一个具有安全性的token,将以任何方式持久化在浏览器。


此后访问其他Web应用的时候,必须携带此token进行访问,业务Web应用会通过本地认证或者转发认证而对token进行校验。


从上图可以简单的分析出三个关键点:


  • Token的生成
  • Token的共享
  • Token校验


Token的生成


方式有多种:


可以通过Web框架对用户信息加密成Token。


Token编码方式也可以为JSON WEB TOKEN(JWT)


也可以是一段MD5,通过字典匹配保存在服务器用户信息与MD5值


Token的共享


浏览器存储有三种方式:


  • Cookie
  • 容量4KB限制
  • 过期时间
  • localStorage
  • 容量5MB限制
  • 生命周期永久
  • sessionStorage
  • 容量5MB限制
  • 生命周期当前会话,关闭浏览器则失效
  • 无法与服务端交互


作为拥有会失效的会话状态,更因选择Cookie存储。那么Cookie的使用是可以在同域共享的,因此在实现SSO的时候复杂度又分为同域跨域


同域的共享比较简单,在应用设置Cookie的Domain属性进行设置,就可以完美的解决。


Token校验


校验分两种情况:


  • 转发给认证中心认证
  •  由谁授权,就由谁进行身份认证。授权与认证是成对的。如果是以Cookie认证,那就是服务端对token进行解密。如果是服务端保存用户信息,则匹配token值。
  • 业务应用自身认证
  •  不需要转发,那就意味着业务应用认证规则与认证中心的认证规则必须是一致的。


设计要点


原则上来讲,只要统一Token的产生和校验方式,无论授权与认证的在哪(认证系统或业务系统),也无论用户信息存储在哪(浏览器、服务器),其实都可以实现单点登录的效果。


此次使用.NET Core MVC框架,以Cookie认证通过业务应用自身认证的方式进行同父域的SSO实现。


为什么要使用Cookie认证方式?


1.会话状态分布在客户浏览器,避免大量用户同时在线对服务端内存容量的压力。


2.横向扩展良好性,可按需增减节点。


统一应用授权认证


将以Core的Cookie认证进行实现,那么意味着每个应用对用户信息的加解密方式需要一致。


因此对AddCookie的设置属性DataProtectionProvider或者TicketDataFormat的加密方式进行重写实现。


.NET Core的SSO实现


Cookie认证


认证中心AddCookie的设置


public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(options =>
               {
                   options.Cookie.Name = "Token";
                   options.Cookie.Domain = ".cg.com";
                   options.Cookie.HttpOnly = true;
                   options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
                   options.LoginPath = "/Account/Login";
                   options.LogoutPath = "/Account/Logout";
                   options.SlidingExpiration = true;
                   //options.DataProtectionProvider = DataProtectionProvider.Create(new DirectoryInfo(@"D:\sso\key"));
                   options.TicketDataFormat = new TicketDataFormat(new AesDataProtector());
               });
        }


业务应用AddCookie的设置


public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(options =>
               {
                   options.Cookie.Name = "Token";
                   options.Cookie.Domain = ".cg.com";
                   options.Events.OnRedirectToLogin = BuildRedirectToLogin;
                   options.Events.OnSigningOut = BuildSigningOut;
                   options.Cookie.HttpOnly = true;
                   options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
                   options.LoginPath = "/Account/Login";
                   options.LogoutPath = "/Account/Logout";
                   options.SlidingExpiration = true;
                   options.TicketDataFormat = new TicketDataFormat(new AesDataProtector());
               });
        }


基于设计要点的“统一应用授权认证”这一点,两者的区别不大,ticket的加密方式统一使用了AES,都指定Cookie.Domain = ".cg.com",保证了Cookie同域共享,设置了HttpOnly避免XSS攻击。


两者区别在于:


options.Events.OnRedirectToLogin = BuildRedirectToLogin;


options.Events.OnSigningOut = BuildSigningOut;


这是为了让业务应用引导跳转到认证中心登录页面。


OnRedirectToLogin是认证失败跳转。OnSigningOut是注销跳转。


/// <summary>
        /// 未登录下,引导跳转认证中心登录页面
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        private static Task BuildRedirectToLogin(RedirectContext<CookieAuthenticationOptions> context)
        {
            var currentUrl = new UriBuilder(context.RedirectUri);
            var returnUrl = new UriBuilder
            {
                Host = currentUrl.Host,
                Port = currentUrl.Port,
                Path = context.Request.Path
            };
            var redirectUrl = new UriBuilder
            {
                Host = "sso.cg.com",
                Path = currentUrl.Path,
                Query = QueryString.Create(context.Options.ReturnUrlParameter, returnUrl.Uri.ToString()).Value
            };
            context.Response.Redirect(redirectUrl.Uri.ToString());
            return Task.CompletedTask;
        }
        /// <summary>
        /// 注销,引导跳转认证中心登录页面
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        private static Task BuildSigningOut(CookieSigningOutContext context)
        {
            var returnUrl = new UriBuilder
            {
                Host = context.Request.Host.Host,
                Port = context.Request.Host.Port ?? 80,
            };
            var redirectUrl = new UriBuilder
            {
                Host = "sso.cg.com",
                Path = context.Options.LoginPath,
                Query = QueryString.Create(context.Options.ReturnUrlParameter, returnUrl.Uri.ToString()).Value
            };
            context.Response.Redirect(redirectUrl.Uri.ToString());
            return Task.CompletedTask;
        }
    }


登录注销


认证中心与业务应用两者的登录注册基本一致。


private async Task<IActionResult> SignIn(User user)
        {
            var claims = new List<Claim>
            {
                new Claim(JwtClaimTypes.Id,user.UserId),
                new Claim(JwtClaimTypes.Name,user.UserName),
                new Claim(JwtClaimTypes.NickName,user.RealName),
            };
            var userPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, "Basic"));
            var returnUrl = HttpContext.Request.Cookies[ReturnUrlKey];
            await HttpContext.SignInAsync(userPrincipal,
                new AuthenticationProperties
                {
                    IsPersistent = true,
                    RedirectUri = returnUrl
                });
            HttpContext.Response.Cookies.Delete(ReturnUrlKey);
            return Redirect(returnUrl ?? "/");
        }
        private async Task SignOut()
        {
            await HttpContext.SignOutAsync();
        }


目录
相关文章
|
21天前
|
消息中间件 前端开发 小程序
一个基于.NET Core构建的简单、跨平台、模块化的商城系统
今天大姚给大家分享一个基于.NET Core构建的简单、跨平台、模块化、完全开源免费(MIT License)的商城系统:Module Shop。
|
21天前
|
算法 C# 数据库
【干货】一份10万字免费的C#/.NET/.NET Core面试宝典
C#/.NET/.NET Core相关技术常见面试题汇总,不仅仅为了面试而学习,更多的是查漏补缺、扩充知识面和大家共同学习进步。该知识库主要由自己平时学习实践总结、网上优秀文章资料收集(这一部分会标注来源)和社区小伙伴提供三部分组成。该份基础面试宝典完全免费,发布两年来收获了广大.NET小伙伴的好评,我会持续更新和改进,欢迎关注我的公众号【追逐时光者】第一时间获取最新更新的面试题内容。
|
21天前
|
数据可视化 网络协议 C#
C#/.NET/.NET Core优秀项目和框架2024年3月简报
公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的介绍、功能特点、使用方式以及部分功能截图等(打不开或者打开GitHub很慢的同学可以优先查看公众号推文,文末一定会附带项目和框架源码地址)。注意:排名不分先后,都是十分优秀的开源项目和框架,每周定期更新分享(欢迎关注公众号:追逐时光者,第一时间获取每周精选分享资讯🔔)。
|
5天前
|
开发框架 前端开发 JavaScript
JavaScript云LIS系统源码ASP.NET CORE 3.1 MVC + SQLserver + Redis医院实验室信息系统源码 医院云LIS系统源码
实验室信息系统(Laboratory Information System,缩写LIS)是一类用来处理实验室过程信息的软件,云LIS系统围绕临床,云LIS系统将与云HIS系统建立起高度的业务整合,以体现“以病人为中心”的设计理念,优化就诊流程,方便患者就医。
14 0
|
19天前
|
Linux API iOS开发
.net core 优势
.NET Core 的优势:跨平台兼容(Windows, macOS, Linux)及容器支持,高性能,支持并行版本控制,丰富的新增API,以及开源。
25 4
|
1月前
|
开发框架 人工智能 .NET
C#/.NET/.NET Core拾遗补漏合集(持续更新)
C#/.NET/.NET Core拾遗补漏合集(持续更新)
|
1月前
|
开发框架 中间件 .NET
C# .NET面试系列七:ASP.NET Core
## 第一部分:ASP.NET Core #### 1. 如何在 controller 中注入 service? 在.NET中,在ASP.NET Core应用程序中的Controller中注入服务通常使用<u>依赖注入(Dependency Injection)</u>来实现。以下是一些步骤,说明如何在Controller中注入服务: 1、创建服务 首先,确保你已经在应用程序中注册了服务。这通常在Startup.cs文件的ConfigureServices方法中完成。例如: ```c# services.AddScoped<IMyService, MyService>(); //
65 0
|
6月前
|
开发框架 前端开发 .NET
ASP.NET Core 核心特性学习笔记「下」
ASP.NET Core 核心特性学习笔记「下」
|
6月前
|
开发框架 前端开发 中间件
ASP.NET Core 核心特性学习笔记「上」
ASP.NET Core 核心特性学习笔记「上」
|
SQL 机器学习/深度学习 Cloud Native
.NET 云原生架构师训练营(模块二 基础巩固 EF Core 更新和迁移)--学习笔记
- 状态 - 自动变更检测 - 不查询删除和更新 - 并发
225 0
.NET 云原生架构师训练营(模块二 基础巩固 EF Core 更新和迁移)--学习笔记