ASP.NET Core微服务之基于IdentityServer建立授权与验证服务(1)

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: Tip: 此篇已加入.NET Core微服务基础系列文章索引一、IdentityServer的预备知识  要学习IdentityServer,事先得了解一下基于Token的验证体系,这是一个庞大的主题,涉及到Token,OAuth&OpenID,JWT,协议规范等等等等,园子里已经有很多介绍的文章了,个人觉得solenovex的这一篇文章《学习IdentityServer4的预备知识》言简意赅,可以快速的看看。

Tip: 此篇已加入.NET Core微服务基础系列文章索引

一、IdentityServer的预备知识

  要学习IdentityServer,事先得了解一下基于Token的验证体系,这是一个庞大的主题,涉及到Token,OAuth&OpenID,JWT,协议规范等等等等,园子里已经有很多介绍的文章了,个人觉得solenovex的这一篇文章《学习IdentityServer4的预备知识》言简意赅,可以快速的看看。另外savaboard的《ASP.NET Core 之 Identity 入门(一)》和《ASP.NET Core 之 Identity 入门(二)》这两篇也可以一看,对Claims和Identity的基本知识讲的比较通俗易懂,深入浅出,有故事情节,哈哈。

  重点关注一下上面这张图(也是来自solenovex的文章),对于一个User(已注册)来说,他会首先向Authorization Server表明自己的身份(比如输入用户名和密码),然后Authorization Server为其发放了一个token,而这个token就好比是把家里的钥匙配了一把(clone)新的,此后该User就可以访问API请求获取Orders(订单)数据了。当然,实际中可能Authorization Server和API Server不在同一个区域内,它们可能只能遥望对方。此外,User还可以基于这个token去访问第三方服务,第三方服务会使用这个API来访问API Server,向其提供token比提供username&password要安全得多。

二、IdentityServer极简介绍

  IdentityServer4(这里只使用版本号为4)是一个基于OpenID Connect和OAuth 2.0的针对ASP.NET Core 2.0的框架。IdentityServer是将规范兼容的OpenID Connect和OAuth 2.0终结点添加到任意ASP.NET Core应用程序的中间件。通常,你构建(或重新使用)包含登录和注销页面的应用程序,IdentityServer中间件会向其添加必要的协议头,以便客户端应用程序可以使用这些标准协议与其对话。

  我们可以用IdentityServer来做啥?

  (1)身份验证服务=>官方认证的OpenID Connect实现

  (2)单点登录/注销(SSO)

  (3)访问受控的API=>为不同的客户提供访问API的令牌,比如:MVC网站、SPA、Mobile App等

  (4)等等等......

三、Started:第一个AuthorizationServer

1.1 建立一个ASP.NET Core空Web项目

  建立ASP.NET Core项目,使用Empty空模板。

  为了更好地查看日志信息,同时考虑到IISExpress启动起来真的很慢,修改lanuchSettings.json文件如下:

{
  "profiles": {
    "Manulife.DNC.MSAD.IdentityServer4Test": {
      "commandName": "Project",
      "launchBrowser": false,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "http://localhost:5000/"
    }
  }
}

1.2 安装并配置IdentityServer4

  Step1.首先安装IdentityServer4:

NuGet>Install-Package IdentityServer4  

  Step2.配置ASP.NET Core管道,即修改Configure方法

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseIdentityServer();
    }

  Step3.为了要把IdentityServer注册到容器中,需要对其进行配置,而这个配置中要包含三个信息:

  (1)哪些API可以使用这个AuthorizationServer

  (2)哪些Client可以使用这个AuthorizationServer

  (3)哪些User可以被这个AuthrizationServer识别并授权

  这里为了快速演示,我们写一个基于内存的静态类来快速填充上面这些信息(实际中,可以持久化在数据库中通过EF等ORM获取,也可以通过Redis获取):

    public class InMemoryConfiguration
    {
        public static IConfiguration Configuration { get; set; }
        /// <summary>
        /// Define which APIs will use this IdentityServer
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<ApiResource> GetApiResources()
        {
            return new[]
            {
                new ApiResource("clientservice", "CAS Client Service"),
                new ApiResource("productservice", "CAS Product Service"),
                new ApiResource("agentservice", "CAS Agent Service")
            };
        }

        /// <summary>
        /// Define which Apps will use thie IdentityServer
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<Client> GetClients()
        {
            return new[]
            {
                new Client
                {
                    ClientId = "client.api.service",
                    ClientSecrets = new [] { new Secret("clientsecret".Sha256()) },
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,
                    AllowedScopes = new [] { "clientservice" }
                },
                new Client
                {
                    ClientId = "product.api.service",
                    ClientSecrets = new [] { new Secret("productsecret".Sha256()) },
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,
                    AllowedScopes = new [] { "clientservice", "productservice" }
                },
                new Client
                {
                    ClientId = "agent.api.service",
                    ClientSecrets = new [] { new Secret("agentsecret".Sha256()) },
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,
                    AllowedScopes = new [] { "agentservice", "clientservice", "productservice" }
                }
            };
        }

        /// <summary>
        /// Define which uses will use this IdentityServer
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<TestUser> GetUsers()
        {
            return new[]
            {
                new TestUser
                {
                    SubjectId = "10001",
                    Username = "edison@hotmail.com",
                    Password = "edisonpassword"
                },
                new TestUser
                {
                    SubjectId = "10002",
                    Username = "andy@hotmail.com",
                    Password = "andypassword"
                },
                new TestUser
                {
                    SubjectId = "10003",
                    Username = "leo@hotmail.com",
                    Password = "leopassword"
                }
            };
        }
    }

   Step4.对于Token签名需要一对公钥和私钥,不过IdentityServer为开发者提供了一个_AddDeveloperSigningCredential()_方法,它会帮我们搞定这个事,并默认存到硬盘中。当切换到生产环境时,还是得使用正儿八经的证书,更换为使用_AddSigningCredential()_方法。

    public void ConfigureServices(IServiceCollection services)
    {
        InMemoryConfiguration.Configuration = this.Configuration;

        services.AddIdentityServer()
            .AddDeveloperSigningCredential()
            .AddTestUsers(InMemoryConfiguration.GetUsers().ToList())
            .AddInMemoryClients(InMemoryConfiguration.GetClients())
            .AddInMemoryApiResources(InMemoryConfiguration.GetApiResources());
    }

1.3 获取你心心念念的Token

  Step1.启动刚刚我们建立的AuthorizationServer程序,这里我们绑定的是5000端口。

  Step2.启动Postman/SoapUI等API测试工具,通过向HTTP Body中填写数据发起POST请求:

  Step3.发送一个错误的数据,看看返回的是啥?(这里输入了一个不在定义列表中的client_id)

  Step4.查看控制台的日志信息:表示获取Token的这个请求成功了,日志中client_secret和password都是不会直接明文显示的。

  Step5.IdentityServer中我们设置这几个API Service的Grant_Type是ResourceOwnerPasswordAndClientCredentials(点击这里了解=>资源拥有者密码凭据许可),因此我们还可以使用ClientCredentials(点击这里了解=>客户端凭据许可),如下所示:

  Step6.再次查看控制台日志信息:这次没有关于User相关的任何信息显示了。

  Step7.基本的开发结束,对于开发阶段,我们使用IdentityServer为开发者提供的临时证书即可,但是后面仍然需要生成一些正儿八经的证书。这里我们通过OpenSSL来生成,首先去官网下载一个,这里使用的是Win64_1.1版本。打开Powershell或者CMD,输入以下命令:

cmd>openssl req -newkey rsa:2048 -nodes -keyout cas.clientservice.key -x509 -days 365 -out cas.clientservice.cer
下面将生成的证书和Key封装成一个文件,以便IdentityServer可以使用它们去正确地签名tokens
cmd>openssl pkcs12 -export -in cas.clientservice.cer -inkey cas.clientservice.key -out cas.clientservice.pfx

  中途会提示让你输入Export Password,这个password后面会用到,记住它。最终导出后的结果如下图所示:

  这里我将其放到了项目结构文件夹中,并设置这个pfx文件为“如果较新则复制”,确保可以在最后生成的目录里边。现在就可以修改一下ConfigureServices()方法了:

    public void ConfigureServices(IServiceCollection services)
    {
        var basePath = PlatformServices.Default.Application.ApplicationBasePath;
        InMemoryConfiguration.Configuration = this.Configuration;

        services.AddIdentityServer()
            //.AddDeveloperSigningCredential()
            .AddSigningCredential(new X509Certificate2(Path.Combine(basePath,
                Configuration["Certificates:CerPath"]),
                Configuration["Certificates:Password"]))
          .AddTestUsers(InMemoryConfiguration.GetUsers().ToList())
          .AddInMemoryClients(InMemoryConfiguration.GetClients())
        .AddInMemoryApiResources(InMemoryConfiguration.GetApiResources());
    }

  这里我将证书的路径和导出密码都写到了配置文件中:

{
  "Certificates": {
    "CerPath": "certificate\\cas.clientservice.pfx",
    "Password": "manulife"
  }
} 

  好,配置正儿八经的证书这一步骤Over。

四、IdentityServer QuickStart-UI

4.1 关于QuickStart UI

  IdentityServer为我们提供了一套UI以便使我们能够快速地开发具有基本功能的认证/授权界面,我们可以去这个地址:https://github.com/IdentityServer/IdentityServer4.Quickstart.UI/tree/release 下载,并将其复制到我们的项目目录中。

  复制完成后,我们的项目结构如下图所示:

4.2 修改DI方法

  (1)使用MVC与静态文件(由于wwwroot下有很多静态资源文件)

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseIdentityServer();
        // for QuickStart-UI
        app.UseStaticFiles();
        app.UseMvcWithDefaultRoute();
    }

  (2)注册MVC

    public void ConfigureServices(IServiceCollection services)
    {
        var basePath = PlatformServices.Default.Application.ApplicationBasePath;
        InMemoryConfiguration.Configuration = this.Configuration;

        services.AddIdentityServer()
            //.AddDeveloperSigningCredential()
            .AddSigningCredential(new X509Certificate2(Path.Combine(basePath,
                Configuration["Certificates:CerPath"]),
                Configuration["Certificates:Password"]))
          .AddTestUsers(InMemoryConfiguration.GetUsers().ToList())
          .AddInMemoryClients(InMemoryConfiguration.GetClients())
          .AddInMemoryApiResources(InMemoryConfiguration.GetApiResources());
        // for QuickStart-UI
        services.AddMvc();
    }

4.3 Run  

  (1)首页(这里由于我已经登录,所以这里会把我的账号显示了出来)

  (2)Logout页,刚刚说到我已经实现Login了,所以我这里Logout一下

  (3)Login页:这里只能识别我们在之前配置的静态User列表中那些User

  登录之后,显示:"You have not given access to any applications",表示我们还没有给他授予访问任何API或网站模块的权限。后续我们会创建API和MVC网站来演示如何对其进行授权和访问。

五、小结

  本篇主要简单的介绍了IdentityServer以及如何基于IdentityServer建立一个基本的AuthorizationServer,如何获取Token,以及集成QuickStart UI实现基本的界面展示。后续还会创建API和MVC网站,来和IdentityServer进行集成,以演示如何对User授予访问API和MVC网站的访问权限。

示例代码

  Click => https://github.com/EdisonChou/EDC.IdentityServer4.Demo

参考资料

identityserver4官方文档》_=> 重点关注那些流程图与术语_

ddrsql,《IdentityServer4之Resource Owner Password Credentials(资源拥有者密码凭据许可)

ddrsql,《IdentityServer4之Client Credentials(客户端凭据许可)

solenovex,《学习Identity Server4的预备知识

solenovex,《使用Identity Server 4建立Authorization Server (1)

solenovex,《使用Identity Server 4建立Authorization Server (2)

solenovex,《使用Identity Server 4建立Authorization Server (3)

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
29天前
|
消息中间件 前端开发 小程序
一个基于.NET Core构建的简单、跨平台、模块化的商城系统
今天大姚给大家分享一个基于.NET Core构建的简单、跨平台、模块化、完全开源免费(MIT License)的商城系统:Module Shop。
|
29天前
|
算法 C# 数据库
【干货】一份10万字免费的C#/.NET/.NET Core面试宝典
C#/.NET/.NET Core相关技术常见面试题汇总,不仅仅为了面试而学习,更多的是查漏补缺、扩充知识面和大家共同学习进步。该知识库主要由自己平时学习实践总结、网上优秀文章资料收集(这一部分会标注来源)和社区小伙伴提供三部分组成。该份基础面试宝典完全免费,发布两年来收获了广大.NET小伙伴的好评,我会持续更新和改进,欢迎关注我的公众号【追逐时光者】第一时间获取最新更新的面试题内容。
|
12天前
|
开发框架 前端开发 JavaScript
JavaScript云LIS系统源码ASP.NET CORE 3.1 MVC + SQLserver + Redis医院实验室信息系统源码 医院云LIS系统源码
实验室信息系统(Laboratory Information System,缩写LIS)是一类用来处理实验室过程信息的软件,云LIS系统围绕临床,云LIS系统将与云HIS系统建立起高度的业务整合,以体现“以病人为中心”的设计理念,优化就诊流程,方便患者就医。
19 0
|
27天前
|
Linux API iOS开发
.net core 优势
.NET Core 的优势:跨平台兼容(Windows, macOS, Linux)及容器支持,高性能,支持并行版本控制,丰富的新增API,以及开源。
25 4
|
29天前
|
开发框架 人工智能 .NET
C#/.NET/.NET Core拾遗补漏合集(持续更新)
在这个快速发展的技术世界中,时常会有一些重要的知识点、信息或细节被忽略或遗漏。《C#/.NET/.NET Core拾遗补漏》专栏我们将探讨一些可能被忽略或遗漏的重要知识点、信息或细节,以帮助大家更全面地了解这些技术栈的特性和发展方向。
|
1天前
|
监控 负载均衡 数据安全/隐私保护
探索微服务架构下的服务网格(Service Mesh)实践
【5月更文挑战第6天】 在现代软件工程的复杂多变的开发环境中,微服务架构已成为构建、部署和扩展应用的一种流行方式。随着微服务架构的普及,服务网格(Service Mesh)作为一种新兴技术范式,旨在提供一种透明且高效的方式来管理微服务间的通讯。本文将深入探讨服务网格的核心概念、它在微服务架构中的作用以及如何在实际项目中落地实施服务网格。通过剖析服务网格的关键组件及其与现有系统的协同工作方式,我们揭示了服务网格提高系统可观察性、安全性和可操作性的内在机制。此外,文章还将分享一些实践中的挑战和应对策略,为开发者和企业决策者提供实用的参考。
|
1天前
|
缓存 监控 数据库
构建高性能微服务架构:后端开发的终极指南
【5月更文挑战第6天】 在现代软件开发的浪潮中,微服务架构以其灵活性、可扩展性和容错性引领着技术潮流。本文深入探索了构建高性能微服务架构的关键要素,从服务划分原则到通信机制,再到持续集成和部署策略。我们将透过实战案例,揭示如何优化数据库设计、缓存策略及服务监控,以确保系统的稳定性和高效运行。文中不仅分享了最佳实践,还讨论了常见的陷阱与解决之道,为后端开发者提供了一条清晰、可行的技术路径。
|
1天前
|
监控 负载均衡 API
微服务架构在现代企业中的应用与挑战
微服务架构已成为现代企业构建灵活且可扩展软件系统的首选。然而,随着其应用的普及,企业也面临着一系列新的挑战。本篇文章将探讨微服务架构的优势、实施时遇到的问题以及解决这些问题的策略。
|
1天前
|
API 持续交付 开发者
构建高效微服务架构:策略与实践
【5月更文挑战第6天】随着现代软件系统的复杂性增加,微服务架构逐渐成为企业开发的首选模式。本文深入分析了构建高效微服务架构的关键策略,并提供了一套实践指南,帮助开发者在保证系统可伸缩性、灵活性和稳定性的前提下,优化后端服务的性能和可维护性。通过具体案例分析,本文将展示如何利用容器化、服务网格、API网关等技术手段,实现微服务的高可用和敏捷部署。
|
2天前
|
监控 负载均衡 持续交付
构建高效微服务架构:后端开发的新趋势
【5月更文挑战第5天】在数字化转型的浪潮中,微服务架构以其灵活性、可扩展性和容错性成为企业追求的技术典范。本文深入探讨了微服务的核心组件、设计原则和实施策略,旨在为后端开发者提供构建和维护高效微服务系统的实用指南。通过分析微服务的最佳实践和常见陷阱,我们揭示了如何优化系统性能、保证服务的高可用性以及如何处理分布式系统中的复杂性。