IdentityServer4 中文文档 -9- (快速入门)使用客户端凭证保护API

IdentityServer4 中文文档 -9- (快速入门)使用客户端凭证保护API


原文:http://docs.identityserver.io/en/release/quickstarts/1_client_credentials.htmlhtml

目 录api

上一篇:IdentityServer4 中文文档 -8- (快速入门)设置和概览
下一篇:IdentityServer4 中文文档 -10- (快速入门)使用密码保护API浏览器

当前快速入门展现了使用 IdentityServer 保护 API 的最基础的场景。服务器

在这个场景中,咱们定义一个 API,同时定义一个 想要访问这个 API 的 客户端。客户端将从 IdentityServer 请求得到一个访问令牌,而后用这个令牌来得到 API 的访问权限。markdown

定义 API

范围(Scopes)用来定义系统中你想要保护的资源,好比 API。app

因为当前演练中咱们使用的是内存配置 —— 添加一个 API,你须要作的只是建立一个 ApiResource 类型的实例,并为它设置合适的属性。ide

向你的项目中添加一份文件(好比:Config.cs),而后添加以下代码:工具

public static IEnumerable<ApiResource> GetApiResources() { return new List<ApiResource> { new ApiResource("api1", "个人 API") }; }public static IEnumerable<ApiResource> GetApiResources() { return new List<ApiResource> { new ApiResource("api1", "个人 API") }; }

定义 客户端

下一步是定义可以访问上述 API 的客户端。post

在该场景中,客户端不会有用户参与交互,而且将使用 IdentityServer 中所谓的客户端密码(Client Secret)来认证。添加以下代码到你的配置中:学习

public static IEnumerable<Client> GetClients() { return new List<Client> { new Client { ClientId = "client", // 没有交互性用户,使用 clientid/secret 实现认证。 AllowedGrantTypes = GrantTypes.ClientCredentials, // 用于认证的密码 ClientSecrets = { new Secret("secret".Sha256()) }, // 客户端有权访问的范围(Scopes) AllowedScopes = { "api1" } } }; }public static IEnumerable<Client> GetClients() { return new List<Client> { new Client { ClientId = "client", // 没有交互性用户,使用 clientid/secret 实现认证。 AllowedGrantTypes = GrantTypes.ClientCredentials, // 用于认证的密码 ClientSecrets = { new Secret("secret".Sha256()) }, // 客户端有权访问的范围(Scopes) AllowedScopes = { "api1" } } }; }

配置 IdentityServer

为了让 IdentityServer 使用你的 Scopes 和 客户端 定义,你须要向 ConfigureServices 方法中添加一些代码。你可使用便捷的扩展方法来实现 —— 它们在幕后会添加相关的存储和数据到 DI 系统中:

public void ConfigureServices(IServiceCollection services) { // 使用内存存储,密钥,客户端和资源来配置身份服务器。 services.AddIdentityServer() .AddTemporarySigningCredential() .AddInMemoryApiResources(Config.GetApiResources()) .AddInMemoryClients(Config.GetClients()); }public void ConfigureServices(IServiceCollection services) { // 使用内存存储,密钥,客户端和资源来配置身份服务器。 services.AddIdentityServer() .AddTemporarySigningCredential() .AddInMemoryApiResources(Config.GetApiResources()) .AddInMemoryClients(Config.GetClients()); }

如今,若是你运行服务器并将浏览器导航到 http://localhost:5000/.well-known/openid-configuration,你应该看能到所谓的 发现文档。你的客户端和 API 将使用这些信息来下载所须要的配置数据。

585526-20170804012838162-2058508363.png

添加 API

下一步,向你的解决方案中添加 API。

你可使用 ASP.NET Core Web API 模板,或者添加 Microsoft.AspNetCore.Mvc 程序包到你的项目中。再一次建议你像以前同样,控制所使用的端口并使用与以前配置 Kestrel 和启动资料相同的技术。该演练假设你已经将你的 API 配置为运行于 http://localhost:5001 之上。

控制器

添加一个新的控制器到你的 API 项目中:

[Route("identity")] [Authorize] public class IdentityController : ControllerBase { [HttpGet()] public IActionResult Get() { return new JsonResult(from c in User.Claims select new { c.Type, c.Value }); } }[Route("identity")] [Authorize] public class IdentityController : ControllerBase { [HttpGet()] public IActionResult Get() { return new JsonResult(from c in User.Claims select new { c.Type, c.Value }); } }

这个控制器将在后面被用于测试受权需求,同时经过API的眼睛(浏览工具)来可视化身份信息。

配置

接下来,添加认证中间件到 API 宿主。该中间件的主要工做是:

  • 验证输入的令牌以确保它来自可信任的发布者(IdentityServer);
  • 验证令牌是否可用于该 api(也就是 Scope)。

IdentityServer4.AccessTokenValidation NuGet 程序包添加到你的 API 项目:

585526-20170804013025959-250281139.png

你还须要添加中间件到你的 HTTP 管道中 —— 必须在添加 MVC 以前添加,好比:

 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions() { Authority = "http://localhost:5000", RequireHttpsMetadata = false, ApiName = "api1" }); app.UseMvc(); }public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions() { Authority = "http://localhost:5000", RequireHttpsMetadata = false, ApiName = "api1" }); app.UseMvc(); }

若是你使用浏览器导航到上述控制器(http://localhost:5001/identity),你应该收到返回的 401 状态码。这意味着你的 API 要求提供证书。

这样一来, API 就是受 IdentityServer 保护的了。

建立客户端

最后一个步骤是编写一个客户端来请求访问令牌,而后使用这个令牌来访问 API。为此你须要为你的解决方案添加一个控制台应用程序。

IdentityServer 上的令牌端点实现了 OAuth 2.0 协议,你应该使用合法的 HTTP 来访问它。然而,咱们有一个叫作 IdentityModel 的客户端库,它将协议交互封装到了一个易于使用的 API 里面。

添加 IdentityModel NuGet 程序包到你的客户端项目中。

585526-20170804012942162-209907233.png

IdentityModel 包含了一个用于 发现端点 的客户端库。这样一来你只须要知道 IdentityServer 的基础地址 —— 实际的端点地址能够从元数据中读取:

// 从元数据中发现端口 var disco = await DiscoveryClient.GetAsync("http://localhost:5000");// 从元数据中发现端口 var disco = await DiscoveryClient.GetAsync("http://localhost:5000");

接着你可使用 TokenClient 类型来请求令牌。为了建立一个该类型的实例,你须要传入令牌端点地址、客户端id和密码。

而后你可使用 RequestClientCredentialsAsync 方法来为你的目标 API 请求一个令牌:

// 请求以得到令牌 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);// 请求以得到令牌 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);

注意:从控制台中复制和粘贴访问令牌到 jwt.io 以检查令牌的合法性。

最后是调用 API。

为了发送访问令牌到 API,你通常要使用 HTTP 受权 header。这能够经过 SetBearerToken 扩展方法来实现:

// 调用API var client = new HttpClient(); client.SetBearerToken(tokenResponse.AccessToken); var response = await client.GetAsync("http://localhost:5001/identity"); if (!response.IsSuccessStatusCode) { Console.WriteLine(response.StatusCode); } else { var content = await response.Content.ReadAsStringAsync(); Console.WriteLine(JArray.Parse(content)); }// 调用API var client = new HttpClient(); client.SetBearerToken(tokenResponse.AccessToken); var response = await client.GetAsync("http://localhost:5001/identity"); if (!response.IsSuccessStatusCode) { Console.WriteLine(response.StatusCode); } else { var content = await response.Content.ReadAsStringAsync(); Console.WriteLine(JArray.Parse(content)); }

最终输出看起来应该是这样的:

585526-20170804013006319-163912838.png

注意:默认状况下访问令牌将包含 scope 身份信息,生命周期(nbf 和 exp),客户端 ID(client_id) 和 发行者名称(iss)。

进一步实践

当前演练目前主要关注的是成功的步骤:

  • 客户端能够请求令牌
  • 客户端可使用令牌来访问 API

你如今能够尝试引起一些错误来学习系统的相关行为,好比:

  • 尝试在 IdentityServer 未运行时(unavailable)链接它
  • 尝试使用一个非法的客户端id或密码来请求令牌
  • 尝试在请求令牌的过程当中请求一个非法的 scope
  • 尝试在 API 未运行时(unavailable)调用它
  • 不向 API 发送令牌
  • 配置 API 为须要不一样于令牌中的 scope

目 录

上一篇:IdentityServer4 中文文档 -8- (快速入门)设置和概览
下一篇:IdentityServer4 中文文档 -10- (快速入门)使用密码保护API

转载于:https://www.cnblogs.com/ideck/p/ids_quickstarts_9.html