如今的应用开发层出不穷,基于浏览器的网页应用,基于微信的公众号、小程序,基于IOS、Android的App,基于Windows系统的桌面应用和UWP应用等等,这么多种类的应用,就给应用的开发带来的挑战,咱们除了分别实现各个应用外,咱们还要考虑各个应用之间的交互,通用模块的提炼,其中身份的认证和受权就是每一个应用必不可少的的一部分。而如今的互联网,对于信息安全要求又十分苛刻,因此一套统一的身份认证和受权就相当重要。html
IdentityServer4就是这样一个框架,IdentityServer4是为ASP.NET CORE量身定制的实现了OpenId Connect和OAuth2.0协议的认证受权中间件。web
下面咱们就来介绍一下相关概念,并梳理下如何集成IdentityServer4。
也可浏览自行整理的IdentityServer4 百度脑图快速了解。json
OpenID 是一个以用户为中心的数字身份识别框架,它具备开放、分散性。OpenID 的建立基于这样一个概念:咱们能够经过 URI (又叫 URL 或网站地址)来认证一个网站的惟一身份,同理,咱们也能够经过这种方式来做为用户的身份认证。小程序
简而言之:OpenId用于身份认证(Authentication)。api
OAuth(开放受权)是一个开放标准,目前的版本是2.0。容许用户受权第三方移动应用访问他们存储在其余服务商上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。
OAuth容许用户提供一个令牌而不是用户名和密码来访问他们存放在特定服务商上的数据。每个令牌受权一个特定的网站内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth能够容许用户受权第三方网站访问他们存储在另外服务提供者的某些特定信息,而非全部内容。
OAuth是OpenID的一个补充,可是彻底不一样的服务。浏览器
简而言之:OAuth2.0 用于受权(Authorization)。关于OAuth2.0也可参考个人另外一篇博文OAuth2.0 知多少。安全
OpenID Connect 1.0 是基于OAuth 2.0协议之上的简单身份层,它容许客户端根据受权服务器的认证结果最终确认终端用户的身份,以及获取基本的用户信息;它支持包括Web、移动、JavaScript在内的全部客户端类型去请求和接收终端用户信息和身份认证会话信息;它是可扩展的协议,容许你使用某些可选功能,如身份数据加密、OpenID提供商发现、会话管理等。服务器
简而言之:OpenId Connect = OIDC = Authentication + Authorization + OAuth2.0。微信
好比,Facebook、Google、QQ、微博都是比较知名的OpenId Connect提供商。网络
了解完OpenId Connect和OAuth2.0的基本概念,咱们再来梳理下涉及到的相关术语:
HTTP提供了一套标准的身份验证框架:服务器能够用来针对客户端的请求发送质询(challenge),客户端根据质询提供身份验证凭证。质询与应答的工做流程以下:服务器端向客户端返回401(Unauthorized,未受权)状态码,并在WWW-Authenticate头中添加如何进行验证的信息,其中至少包含有一种质询方式。而后客户端能够在请求中添加Authorization头进行验证,其Value为身份验证的凭证信息。
Bearer认证(也叫作令牌认证)是一种HTTP认证方案,其中包含的安全令牌的叫作Bearer Token。所以Bearer认证的核心是Token。那如何确保Token的安全是重中之重。一种方式是使用Https,另外一种方式就是对Token进行加密签名。而JWT就是一种比较流行的Token编码方式。
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准(RFC 7519)。该token被设计为紧凑且安全的,特别适用于分布式站点的单点登陆(SSO)场景。JWT的声明通常被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也能够增长一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
JWT有三部分组成:
<header>.<payload>.<signature>
alg
和typ
组成,alg
是algorithm的缩写,typ
是type的缩写,指定token的类型。该部分使用Base64Url
编码。BaseURL
编码。HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
OAuth2.0 定义了四种受权模式:
客户端凭证模式,是最简单的受权模式,由于受权的流程仅发生在Client与Identity Server之间。
该模式的适用场景为服务器与服务器之间的通讯。好比对于一个电子商务网站,将订单和物流系统分拆为两个服务分别部署。订单系统须要访问物流系统进行物流信息的跟踪,物流系统须要访问订单系统的快递单号信息进行物流信息的定时刷新。而这两个系统之间服务的受权就能够经过这种模式来实现。
Resource Owner其实就是User,因此能够直译为用户名密码模式。密码模式相较于客户端凭证模式,多了一个参与者,就是User。经过User的用户名和密码向Identity Server申请访问令牌。这种模式下要求客户端不得储存密码。但咱们并不能确保客户端是否储存了密码,因此该模式仅适用于受信任的客户端。不然会发生密码泄露的危险。该模式不推荐使用。
受权码模式是一种混合模式,是目前功能最完整、流程最严密的受权模式。它主要分为两大步骤:认证和受权。
其流程为:
简化模式是相对于受权码模式而言的。其再也不须要【Client】的参与,全部的认证和受权都是经过浏览器来完成的。
经过以上知识点的梳理,咱们对OpenId Connect 和OAuth2.0的一些相关概念有了大体认识。而IdentityServer4是为ASP.NET CORE量身定制的实现了OpenId Connect和OAuth2.0协议的认证受权中间件。
因此天然而然咱们对IdentityServer4有了基础的认识。下面就来介绍如何集成IdentityServer4。其主要分为三步:
做为一个独立的Identity Server,它必须知道哪些资源须要保护,必须知道哪些客户端可以容许访问,这是配置的基础。
因此IdentityServer中间件的配置的核心就是:
public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMvc(); // configure identity server with in-memory stores, keys, clients and scopes services.AddIdentityServer() .AddDeveloperSigningCredential() //配置身份资源 .AddInMemoryIdentityResources(Config.GetIdentityResources()) //配置API资源 .AddInMemoryApiResources(Config.GetApiResources()) //预置容许验证的Client .AddInMemoryClients(Config.GetClients()) .AddTestUsers(Config.GetUsers()); services.AddAuthentication() //添加Google第三方身份认证服务(按需添加) .AddGoogle("Google", options => { options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; options.ClientId = "434483408261-55tc8n0cs4ff1fe21ea8df2o443v2iuc.apps.googleusercontent.com"; options.ClientSecret = "3gcoTrEDPPJ0ukn_aYYT6PWo"; }) //若是当前IdentityServer不提供身份认证服务,还能够添加其余身份认证服 务提供商 .AddOpenIdConnect("oidc", "OpenID Connect", options => { options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; options.SignOutScheme = IdentityServerConstants.SignoutScheme; options.Authority = "https://demo.identityserver.io/"; options.ClientId = "implicit"; options.TokenValidationParameters = new TokenValidationParameters { NameClaimType = "name", RoleClaimType = "role" }; }); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } //添加IdentityServer中间件到Pipeline app.UseIdentityServer(); app.UseStaticFiles(); app.UseMvcWithDefaultRoute(); }
配置完,添加IdentityServer到Pipeline便可。
若是要支持第三方登陆服务或本身实现的OpenId Connect服务,则须要额外配置下身份认证中间件。
配置完Identity Server,接下来咱们该思考如何来保护Resources,以及如何将全部的认证和受权请求导流到Identity Server呢?
在此以前,咱们仍是要梳理下Client访问Resources的请求顺序:
因此针对要保护的资源,咱们须要如下配置:
代码示例:
//使用[Authorize]特性,来显式指定受保护的资源 [Route("[controller]")] [Authorize] public class IdentityController : ControllerBase { [HttpGet] public IActionResult Get() { return new JsonResult(from c in User.Claims select new { c.Type, c.Value }); } }
public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMvcCore() .AddAuthorization() .AddJsonFormatters(); //指定认证方案 services.AddAuthentication("Bearer") //添加Token验证服务到DI .AddIdentityServerAuthentication(options => { //指定受权地址 options.Authority = "http://localhost:5000"; options.RequireHttpsMetadata = false; options.ApiName = "api1"; }); } public void Configure(IApplicationBuilder app) { //添加认证中间件到Pipeline app.UseAuthentication(); app.UseMvc(); } }
资源和认证服务器都配置完毕,接下来客户端就能够直接访问了。
若是针对控制台客户端应用,三步走就能够访问Api:
// discover endpoints from metadata var disco = await DiscoveryClient.GetAsync("http://localhost:5000"); // request token(使用的是ClientCredentials受权类型) var tokenClient = new TokenClient(disco.TokenEndpoint, "client", "secret"); var tokenResponse = await tokenClient.RequestClientCredentialsAsync("api1") if (tokenResponse.IsError) { Console.WriteLine(tokenResponse.Error); return; } Console.WriteLine(tokenResponse.Json); Console.WriteLine("\n\n"); // call api var client = new HttpClient(); client.SetBearerToken(tokenResponse.AccessToken);
若是针对ASP.NET Web控制台客户端,咱们先来回答一个问题:
回答完上面的问题,咱们也就梳理出了配置要点:
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); services.AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("Cookies") .AddOpenIdConnect("oidc", options => { options.SignInScheme = "Cookies"; options.Authority = "http://localhost:5000"; options.RequireHttpsMetadata = false; options.ClientId = "mvc"; options.SaveTokens = true; }); } public void Configure(IApplicationBuilder app, IHostingEnvironment env { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseAuthentication(); app.UseStaticFiles(); app.UseMvcWithDefaultRoute(); }
本文经过介绍IdentityServer4涉及到的术语和相关概念,再结合官方实例,梳理了集成IdentityServer4的大体思路。而关于如何与ASP.NET Identity、EF Core集成,本文并未涉及,详参官方文档。
Identity Server 官方文档
dentityServer4 中文文档与实战
ASP.NET Core 认证与受权[4]:JwtBearer认证
Bearer Authentication
JSON Web Token
理解OAuth 2.0
Identity Server 受权类型