首先感谢晓晨Master和EdisonChou的审稿!也感谢正在阅读的您!

引言

通常,服务所公开的资源和 API 必须仅限受信任的特定用户和客户端访问。那进行 API 级别信任决策的第一步就是身份认证——确定用户身份是否可靠。

在微服务场景中,身份认证通常统一处理。一般有两种实现形式:

  1. 基于API 网关中心化认证:要求客户端必须都通过网关访问微服务。(这就要求提供一种安全机制来认证请求是来自于网关。)

  2. 基于安全令牌服务(STS)认证:所有的客户端先从STS获取令牌,然后请求时携带令牌完成认证。

而本节所讲的Identity microservice就是使用第二种身份认证方式。

服务简介

Identity microservice 主要用于统一的身份认证和授权,为其他服务提供支撑。

提到认证,大家最熟悉不过的当属Cookie认证了,它也是目前使用最多的认证方式。但Cookie认证也有其局限性:不支持跨域、移动端不友好等。而从当前的架构来看,需要支持移动端、Web端、微服务间的交叉认证授权,所以传统的基于Cookie的本地认证方案就行不通了。我们就需要使用远程认证的方式来提供统一的认证授权机制。
而远程认证方式当属:OAuth2.0和OpenID Connect了。借助OAuth2.0和OpenID Connect即可实现类似下图的认证体系:

而如何实现呢,借助:

  1. ASP.NET Core Identity
  2. IdentityServer4

基于Cookie的认证和基于Token的认证的差别如下所示:

架构模式

该微服务作为支撑服务,并没有选择复杂的架构模式,使用了MVC单层架构,使用EF Core ORM框架用于数据持久化,SQL Server数据库。使用Autofac IOC框架替换了默认依赖注入框架。

项目结构如下所示:

核心技术选型:

  1. MVC单层架构
  2. EF Core
  3. ASP.NET Core Identity
  4. IdentityServer4
  5. SQL Server 数据库
  6. Autofac

PS:对ASP.NET Core Identity、IdentityServer4以及OAuth2.0不了解的,请先行阅读文末参考资料补课!!!

下面就着重讲解ASP.NET Core Identity和IdentityServer4在本服务中的使用。

ASP.NET Core Identity && IdentityServer4简介

ASP.NET Core Identity用于构建ASP.NET Core Web应用程序的成员资格系统,包括成员资格,登录和用户数据(包括登录信息、角色和声明)。
ASP.NET Core Identity封装了User、Role、Claim等身份信息,便于我们快速完成登录功能的实现,并且支持第三方登录(Google、Facebook、QQ、Weixin等,支持开箱即用[第三方身份提供商列表]),以及双重验证,同时内置支持Bearer 认证(令牌认证)。

虽然ASP.NET Core Identity已经完成了绝大多数的功能,且支持第三方登录(第三方为其用户颁发令牌),但若要为本地用户颁发令牌,则需要自己实现令牌的颁发和验证逻辑。换句话说,我们需要自行实现OpenId Connect协议。

OpenID Connect 1.0 是基于OAuth 2.0协议之上的简单身份层,它允许客户端根据授权服务器的认证结果最终确认终端用户的身份,以及获取基本的用户信息。

而IdentityServer4就是为ASP.NET Core量身定制的实现了OpenId Connect和OAuth2.0协议的认证授权中间件。IdentityServer4在ASP.NET Core Identity的基础上,提供令牌的颁发验证等。

认证流程简介

在ASP.NET Core中使用的是基于申明(Claim)的认证,而什么是申明(Cliam)呢?

Claim 是关于一个人或组织的某个主题的陈述,比如:一个人的名称,角色,个人喜好,种族,特权,社团,能力等等。它本质上就是一个键值对,是一种非常通用的保存用户信息的方式,可以很容易的将认证和授权分离开来,前者用来表示用户是/不是什么,后者用来表示用户能/不能做什么。在认证阶段我们通过用户信息获取到用户的Claims,而授权便是对这些的Claims的验证,如:是否拥有Admin的角色,姓名是否叫XXX等等。

认证主要与以下几个核心对象打交道:

  1. Claim(身份信息)
  2. ClaimsIdentity(身份证)
  3. ClaimsPrincipal (身份证持有者)
  4. AuthorizationToken (授权令牌)
  5. IAuthenticationScheme(认证方案)
  6. IAuthenticationHandler(与认证方案对应的认证处理器)
  7. IAuthenticationService (向外提供统一的认证服务接口)

那其认证流程是怎样的呢?

用户打开登录界面,输入用户名密码先行登录,服务端先行校验用户名密码是否有效,有效则返回用户实例(User),这时进入认证准备阶段,根据用户实例携带的身份信息(Claim),创建身份证(ClaimsIdentity),然后将身份证交给身份证持有者(ClaimsPrincipal)持有。接下来进入真正的认证阶段,根据配置的认证方案(IAuthenticationScheme),使用相对应的认证处理器(IAuthenticationHandler)进行认证 。认证成功后发放授权令牌(AuthorizationToken)。该授权令牌包含后续授权阶段需要的全部信息。

授权流程简介

授权就是对于用户身份信息(Claims)的验证,,授权又分以下几种种:

  1. 基于Role的授权
  2. 基于Scheme的授权
  3. 基于Policy的授权

授权主要与以下几个核心对象打交道:

  1. IAuthorizationRequirement(授权条件)
  2. IAuthorizationService(授权服务)
  3. AuthorizationPolicy(授权策略)
  4. IAuthorizationHandler (授权处理器)
  5. AuthorizationResult(授权结果)

那授权流程是怎样的呢?

当收到授权请求后,由授权服务(IAuthorizationService)根据资源上指定的授权策略(AuthorizationPolicy)中包含的授权条件(IAuthorizationRequirement),找到相对应的授权处理器(IAuthorizationHandler )来判断授权令牌中包含的身份信息是否满足授权条件,并返回授权结果。

中间件集成

简单了解了下认证和授权流程后,我们来了解Identity microservice是如何集成相关中间件的。

1. 首先是映射自定义扩展的User和Role

 // 映射自定义的User,Role
services.AddIdentity<ApplicationUser, IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>()//配置使用EF持久化存储.AddDefaultTokenProviders();//配置默认的TokenProvider用于变更密码和修改email时生成Token

2. 配置IdentityServer服务

// Adds IdentityServer
services.AddIdentityServer(x =>
{x.IssuerUri = "null";x.Authentication.CookieLifetime = TimeSpan.FromHours(2);
})
.AddSigningCredential(Certificate.Get())
.AddAspNetIdentity<ApplicationUser>()
.AddConfigurationStore(options =>
{options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString,sqlServerOptionsAction: sqlOptions =>{sqlOptions.MigrationsAssembly(migrationsAssembly);//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);});
})
.AddOperationalStore(options =>
{options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString,sqlServerOptionsAction: sqlOptions =>{sqlOptions.MigrationsAssembly(migrationsAssembly);//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);});
})
.Services.AddTransient<IProfileService, ProfileService>();

IdentityServer默认直接在内存中存储配置数据(客户端和资源)和操作数据(令牌,代码和和用户的授权信息consents)。这显然在生产环境是不合适的,如果服务所在主机宕机,那么内存中的数据就会丢失,所以有必要持久化到数据库。
其中AddConfigurationStoreAddOperationalStore扩展方法就是用来来指定配置数据和操作数据基于EF进行持久化。

3. 添加IdentityServer中间件

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{// .....// Adds IdentityServerapp.UseIdentityServer();
}

4. 预置种子数据

从已知的体系结构来说,我们需要预置Client和Resource:

  1. Client
public static IEnumerable<Client> GetClients(Dictionary<string,string> clientsUrl)
{return new List<Client>{// SPA OpenId Client Client(Implicit)new Client// Xamarin Client(Hybrid)new Client// MVC Client(Hybrid)new Client// MVC TEST Client(Hybrid)new Client// Locations Swagger UI(Implicit)new Client// Marketing Swagger UI(Implicit)new Client// Basket Swagger UI(Implicit)new Client// Ordering Swagger UI(Implicit)new Client// Mobile Shopping Aggregattor Swagger UI(Implicit)new Client// Web Shopping Aggregattor Swagger UI(Implicit)new Client};
}
  1. IdentityResources
public static IEnumerable<IdentityResource> GetResources()
{return new List<IdentityResource>{new IdentityResources.OpenId(),new IdentityResources.Profile()};
}
  1. ApiResources
public static IEnumerable<ApiResource> GetApis()
{return new List<ApiResource>{new ApiResource("orders", "Orders Service"),new ApiResource("basket", "Basket Service"),new ApiResource("marketing", "Marketing Service"),new ApiResource("locations", "Locations Service"),new ApiResource("mobileshoppingagg", "Mobile Shopping Aggregator"),new ApiResource("webshoppingagg", "Web Shopping Aggregator"),new ApiResource("orders.signalrhub", "Ordering Signalr Hub")};
}

5. 迁移数据库上下文

下面就把提前在代码预置的种子数据迁移到数据库中,我们如何做呢?IdentityServer为配置数据和操作数据分别定义了DBContext用于持久化,配置数据对应ConfigurationDbContext,操作数据对应PersistedGrantDbContext。代码如下所示:

public static void Main(string[] args)
{BuildWebHost(args).MigrateDbContext<PersistedGrantDbContext>((_, __) => { })//迁移操作数据库.MigrateDbContext<ApplicationDbContext>((context, services) =>{var env = services.GetService<IHostingEnvironment>();var logger = services.GetService<ILogger<ApplicationDbContextSeed>>();var settings = services.GetService<IOptions<AppSettings>>();new ApplicationDbContextSeed().SeedAsync(context, env, logger, settings).Wait();})//迁移用户数据库.MigrateDbContext<ConfigurationDbContext>((context,services)=> {var configuration = services.GetService<IConfiguration>();new ConfigurationDbContextSeed().SeedAsync(context, configuration).Wait();})//迁移配置数据库.Run();
}

至此,本服务的核心代码已解析完毕。

最终的生成的数据库如下图所示:

最后

本文从业务和技术上对本服务进行剖析,介绍了其技术选型,并紧接着简要介绍了ASP.NET Core Identity和IdentityServer4,最后分析源码,一步步揭开其神秘的面纱。至于客户端和其他微服务服务如何使用Identity microservice进行认证和授权,我将在后续文章再行讲解。

如果对ASP.NET Core Idenity和IdentityServer4不太了解,建议大家博客园阅读雨夜朦胧、晓晨Master和Savorboard
的博客进行系统学习后,再重读本文,相信你对Identity microservice的实现机制豁然开朗。

参考资料

雨夜朦胧 -- ASP.NET Core 认证与授权:初识认证/授权
Savorboard -- ASP.NET Core 之 Identity 入门(一)
晓晨Master -- IdentityServer(14)- 通过EntityFramework Core持久化配置和操作数据
IdentityServer4 知多少
OAuth2.0 知多少
.NET Core微服务之基于Ocelot+IdentityServer实现统一验证与授权

eShopOnContainers 知多少[3]:Identity microservice相关推荐

  1. eShopOnContainers 知多少[2]:Run起来

    环境准备 Win10(开启Hyper-V) .NET Core SDK Docker for Windows VS2017 or VS Code Git SQL Server Management S ...

  2. eShopOnContainers 知多少[8]:Ordering microservice

    1. 引言 Ordering microservice(订单微服务)就是处理订单的了,它与前面讲到的几个微服务相比要复杂的多.主要涉及以下业务逻辑: 订单的创建.取消.支付.发货 库存的扣减 2. 架 ...

  3. eShopOnContainers 知多少[4]:Catalog microservice

    引言 Catalog microservice(目录微服务)维护着所有产品信息,包括库存.价格.所以该微服务的核心业务为: 产品信息的维护 库存的更新 价格的维护 架构模式 如上图所示,本微服务采用简 ...

  4. eShopOnContainers 知多少[7]:Basket microservice

    引言 Basket microservice(购物车微服务)主要用于处理购物车的业务逻辑,包括: 购物车商品的CRUD 订阅商品价格更新事件,进行购物车商品同步处理 购物车结算事件发布 订阅订单成功创 ...

  5. eShopOnContainers 知多少[10]:部署到 K8S | AKS

    1. 引言 断断续续,感觉这个系列又要半途而废了.趁着假期,赶紧再更一篇,介绍下如何将eShopOnContainers部署到K8S上,进而实现大家常说的微服务上云. 2. 先了解下 Helm 读过我 ...

  6. eShopOnContainers 知多少[9]:Ocelot gateways

    引言 客户端与微服务的通信问题永远是一个绕不开的问题,对于小型微服务应用,客户端与微服务可以使用直连的方式进行通信,但对于对于大型的微服务应用我们将不得不面对以下问题: 如何降低客户端到后台的请求数量 ...

  7. eShopOnContainers 知多少[5]:EventBus With RabbitMQ

    1. 引言 事件总线这个概念对你来说可能很陌生,但提到观察者(发布-订阅)模式,你也许就很熟悉.事件总线是对发布-订阅模式的一种实现.它是一种集中式事件处理机制,允许不同的组件之间进行彼此通信而又不需 ...

  8. eShopOnContainers 知多少[12]:Envoy gateways

    1. 引言 在最新的eShopOnContainers  3.0 中Ocelot 网关被Envoy Proxy 替换.下面就来简要带大家了解下Envoy,并尝试梳理下为什么要使用Envoy替代Ocel ...

  9. eShopOnContainers 知多少[11]:服务间通信之gRPC

    1. 引言 最近翻看最新3.0 eShopOncontainers源码,发现其在架构选型中补充了 gRPC 进行服务间通信.那就索性也写一篇,作为系列的补充. 2. gRPC 老规矩,先来理一下gRP ...

最新文章

  1. oracle主从关系表查询,Oracle 主从表联合查询解决方法
  2. QT中关于按钮以及菜单栏工具添加图标,以及快捷方式
  3. 在腾讯云上创建您的SQL Cluster(1)
  4. 分支和循环_月隐学python第5课
  5. oracle pctlist,oracle pctfree和pctused详解
  6. EasyUI的databox取值
  7. win8下hosts保存文档失败,提示:请检查文件是否被另一个应用程序打开
  8. QProcess 使用
  9. 制造行业主数据治理项目实施心得
  10. CAD批量提取数值lisp插件_CAD批量获取文本坐标及内容
  11. Scrum敏捷开发模式介绍与实践
  12. 各品牌智能电视刷机怎么寻找对应固件包?详细图文教程分享
  13. Keras学习教程七
  14. 网络工程属于计算机还是通信,通信工程属于计算机大类吗 哪个大类
  15. Safair浏览器 时间戳转化兼容性问题。
  16. VALSE 4月12日 下午 第一会场 深度学习模型设计 会议记录
  17. 评价神经网络性能的指标,神经网络是参数模型吗
  18. 图片转world文档 Excel excel 新
  19. 矩阵初等行变换的技巧
  20. 大学期间所有课设及大作业源代码

热门文章

  1. 去掉iPhone safari下手机号码默认的下划线
  2. 基于卷积神经网络的高光谱图像分类
  3. 深耕城市治理场景,百度智能云联合慧联无限推内涝智能检测预警
  4. java计算机毕业设计广西科技大学第一附属医院陪护椅管理源码+mysql数据库+系统+lw文档+部署
  5. 数据库 SQL 时间处理函数 获取指定或最近期时间范围内 日期 月份 年份 列表
  6. PYNQ-z2 联网
  7. HBuilder 打包 H5 APP 进行认证登录
  8. C#实现Windows资源管理器 C# File Explorer
  9. 遵循gpl协议 采用jar包_开源协议适用范围及其对软件著作权侵权判定的影响
  10. LED 数码管显示编码