eShopOnContainers 知多少[3]:Identity microservice
首先感谢晓晨Master和EdisonChou的审稿!也感谢正在阅读的您!
引言
通常,服务所公开的资源和 API 必须仅限受信任的特定用户和客户端访问。那进行 API 级别信任决策的第一步就是身份认证——确定用户身份是否可靠。
在微服务场景中,身份认证通常统一处理。一般有两种实现形式:
基于API 网关中心化认证:要求客户端必须都通过网关访问微服务。(这就要求提供一种安全机制来认证请求是来自于网关。)
基于安全令牌服务(STS)认证:所有的客户端先从STS获取令牌,然后请求时携带令牌完成认证。
而本节所讲的Identity microservice就是使用第二种身份认证方式。
服务简介
Identity microservice 主要用于统一的身份认证和授权,为其他服务提供支撑。
提到认证,大家最熟悉不过的当属Cookie认证了,它也是目前使用最多的认证方式。但Cookie认证也有其局限性:不支持跨域、移动端不友好等。而从当前的架构来看,需要支持移动端、Web端、微服务间的交叉认证授权,所以传统的基于Cookie的本地认证方案就行不通了。我们就需要使用远程认证的方式来提供统一的认证授权机制。
而远程认证方式当属:OAuth2.0和OpenID Connect了。借助OAuth2.0和OpenID Connect即可实现类似下图的认证体系:
而如何实现呢,借助:
- ASP.NET Core Identity
- IdentityServer4
基于Cookie的认证和基于Token的认证的差别如下所示:
架构模式
该微服务作为支撑服务,并没有选择复杂的架构模式,使用了MVC单层架构,使用EF Core ORM框架用于数据持久化,SQL Server数据库。使用Autofac IOC框架替换了默认依赖注入框架。
项目结构如下所示:
核心技术选型:
- MVC单层架构
- EF Core
- ASP.NET Core Identity
- IdentityServer4
- SQL Server 数据库
- 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等等。
认证主要与以下几个核心对象打交道:
- Claim(身份信息)
- ClaimsIdentity(身份证)
- ClaimsPrincipal (身份证持有者)
- AuthorizationToken (授权令牌)
- IAuthenticationScheme(认证方案)
- IAuthenticationHandler(与认证方案对应的认证处理器)
- IAuthenticationService (向外提供统一的认证服务接口)
那其认证流程是怎样的呢?
用户打开登录界面,输入用户名密码先行登录,服务端先行校验用户名密码是否有效,有效则返回用户实例(User),这时进入认证准备阶段,根据用户实例携带的身份信息(Claim),创建身份证(ClaimsIdentity),然后将身份证交给身份证持有者(ClaimsPrincipal)持有。接下来进入真正的认证阶段,根据配置的认证方案(IAuthenticationScheme),使用相对应的认证处理器(IAuthenticationHandler)进行认证 。认证成功后发放授权令牌(AuthorizationToken)。该授权令牌包含后续授权阶段需要的全部信息。
授权流程简介
授权就是对于用户身份信息(Claims)的验证,,授权又分以下几种种:
- 基于Role的授权
- 基于Scheme的授权
- 基于Policy的授权
授权主要与以下几个核心对象打交道:
- IAuthorizationRequirement(授权条件)
- IAuthorizationService(授权服务)
- AuthorizationPolicy(授权策略)
- IAuthorizationHandler (授权处理器)
- 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)。这显然在生产环境是不合适的,如果服务所在主机宕机,那么内存中的数据就会丢失,所以有必要持久化到数据库。
其中AddConfigurationStore
和AddOperationalStore
扩展方法就是用来来指定配置数据和操作数据基于EF进行持久化。
3. 添加IdentityServer中间件
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{// .....// Adds IdentityServerapp.UseIdentityServer();
}
4. 预置种子数据
从已知的体系结构来说,我们需要预置Client和Resource:
- 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};
}
- IdentityResources
public static IEnumerable<IdentityResource> GetResources()
{return new List<IdentityResource>{new IdentityResources.OpenId(),new IdentityResources.Profile()};
}
- 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相关推荐
- eShopOnContainers 知多少[2]:Run起来
环境准备 Win10(开启Hyper-V) .NET Core SDK Docker for Windows VS2017 or VS Code Git SQL Server Management S ...
- eShopOnContainers 知多少[8]:Ordering microservice
1. 引言 Ordering microservice(订单微服务)就是处理订单的了,它与前面讲到的几个微服务相比要复杂的多.主要涉及以下业务逻辑: 订单的创建.取消.支付.发货 库存的扣减 2. 架 ...
- eShopOnContainers 知多少[4]:Catalog microservice
引言 Catalog microservice(目录微服务)维护着所有产品信息,包括库存.价格.所以该微服务的核心业务为: 产品信息的维护 库存的更新 价格的维护 架构模式 如上图所示,本微服务采用简 ...
- eShopOnContainers 知多少[7]:Basket microservice
引言 Basket microservice(购物车微服务)主要用于处理购物车的业务逻辑,包括: 购物车商品的CRUD 订阅商品价格更新事件,进行购物车商品同步处理 购物车结算事件发布 订阅订单成功创 ...
- eShopOnContainers 知多少[10]:部署到 K8S | AKS
1. 引言 断断续续,感觉这个系列又要半途而废了.趁着假期,赶紧再更一篇,介绍下如何将eShopOnContainers部署到K8S上,进而实现大家常说的微服务上云. 2. 先了解下 Helm 读过我 ...
- eShopOnContainers 知多少[9]:Ocelot gateways
引言 客户端与微服务的通信问题永远是一个绕不开的问题,对于小型微服务应用,客户端与微服务可以使用直连的方式进行通信,但对于对于大型的微服务应用我们将不得不面对以下问题: 如何降低客户端到后台的请求数量 ...
- eShopOnContainers 知多少[5]:EventBus With RabbitMQ
1. 引言 事件总线这个概念对你来说可能很陌生,但提到观察者(发布-订阅)模式,你也许就很熟悉.事件总线是对发布-订阅模式的一种实现.它是一种集中式事件处理机制,允许不同的组件之间进行彼此通信而又不需 ...
- eShopOnContainers 知多少[12]:Envoy gateways
1. 引言 在最新的eShopOnContainers 3.0 中Ocelot 网关被Envoy Proxy 替换.下面就来简要带大家了解下Envoy,并尝试梳理下为什么要使用Envoy替代Ocel ...
- eShopOnContainers 知多少[11]:服务间通信之gRPC
1. 引言 最近翻看最新3.0 eShopOncontainers源码,发现其在架构选型中补充了 gRPC 进行服务间通信.那就索性也写一篇,作为系列的补充. 2. gRPC 老规矩,先来理一下gRP ...
最新文章
- oracle主从关系表查询,Oracle 主从表联合查询解决方法
- QT中关于按钮以及菜单栏工具添加图标,以及快捷方式
- 在腾讯云上创建您的SQL Cluster(1)
- 分支和循环_月隐学python第5课
- oracle pctlist,oracle pctfree和pctused详解
- EasyUI的databox取值
- win8下hosts保存文档失败,提示:请检查文件是否被另一个应用程序打开
- QProcess 使用
- 制造行业主数据治理项目实施心得
- CAD批量提取数值lisp插件_CAD批量获取文本坐标及内容
- Scrum敏捷开发模式介绍与实践
- 各品牌智能电视刷机怎么寻找对应固件包?详细图文教程分享
- Keras学习教程七
- 网络工程属于计算机还是通信,通信工程属于计算机大类吗 哪个大类
- Safair浏览器 时间戳转化兼容性问题。
- VALSE 4月12日 下午 第一会场 深度学习模型设计 会议记录
- 评价神经网络性能的指标,神经网络是参数模型吗
- 图片转world文档 Excel excel 新
- 矩阵初等行变换的技巧
- 大学期间所有课设及大作业源代码
热门文章
- 去掉iPhone safari下手机号码默认的下划线
- 基于卷积神经网络的高光谱图像分类
- 深耕城市治理场景,百度智能云联合慧联无限推内涝智能检测预警
- java计算机毕业设计广西科技大学第一附属医院陪护椅管理源码+mysql数据库+系统+lw文档+部署
- 数据库 SQL 时间处理函数 获取指定或最近期时间范围内 日期 月份 年份 列表
- PYNQ-z2 联网
- HBuilder 打包 H5 APP 进行认证登录
- C#实现Windows资源管理器 C# File Explorer
- 遵循gpl协议 采用jar包_开源协议适用范围及其对软件著作权侵权判定的影响
- LED 数码管显示编码