IdentityServer4 中文文檔 -9- (快速入門)使用客戶端憑證保護API
原文:http://docs.identityserver.io/en/release/quickstarts/1_client_credentials.html
上一篇:IdentityServer4 中文文檔 -8- (快速入門)設置和概覽
下一篇:IdentityServer4 中文文檔 -10- (快速入門)使用密碼保護API
當前快速入門展示了使用 IdentityServer 保護 API 的最基礎的場景。
在這個場景中,我們定義一個 API,同時定義一個 想要訪問這個 API 的 客戶端。客戶端將從 IdentityServer 請求獲得一個訪問令牌,然后用這個令牌來獲得 API 的訪問權限。
定義 API
范圍(Scopes)用來定義系統中你想要保護的資源,比如 API。
由於當前演練中我們使用的是內存配置 —— 添加一個 API,你需要做的只是創建一個 ApiResource 類型的實例,並為它設置合適的屬性。
向你的項目中添加一份文件(比如:Config.cs),然后添加如下代碼:
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("api1", "我的 API")
};
}
定義 客戶端
下一步是定義能夠訪問上述 API 的客戶端。
在該場景中,客戶端不會有用戶參與交互,並且將使用 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" }
}
};
}
配置 IdentityServer
為了讓 IdentityServer 使用你的 Scopes 和 客戶端 定義,你需要向 ConfigureServices 方法中添加一些代碼。你可以使用便捷的擴展方法來實現 —— 它們在幕后會添加相關的存儲和數據到 DI 系統中:
public void ConfigureServices(IServiceCollection services)
{
// 使用內存存儲,密鑰,客戶端和資源來配置身份服務器。
services.AddIdentityServer()
.AddTemporarySigningCredential()
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients());
}
現在,如果你運行服務器並將瀏覽器導航到 http://localhost:5000/.well-known/openid-configuration,你應該看能到所謂的 發現文檔。你的客戶端和 API 將使用這些信息來下載所需要的配置數據。

添加 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 });
}
}
這個控制器將在后面被用於測試授權需求,同時通過API的眼睛(瀏覽工具)來可視化身份信息。
配置
接下來,添加認證中間件到 API 宿主。該中間件的主要工作是:
- 驗證輸入的令牌以確保它來自可信任的發布者(IdentityServer);
- 驗證令牌是否可用於該 api(也就是 Scope)。
將 IdentityServer4.AccessTokenValidation NuGet 程序包添加到你的 API 項目:

你還需要添加中間件到你的 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();
}
如果你使用瀏覽器導航到上述控制器(http://localhost:5001/identity),你應該收到返回的 401 狀態碼。這意味着你的 API 要求提供證書。
這樣一來, API 就是受 IdentityServer 保護的了。
創建客戶端
最后一個步驟是編寫一個客戶端來請求訪問令牌,然后使用這個令牌來訪問 API。為此你需要為你的解決方案添加一個控制台應用程序。
IdentityServer 上的令牌端點實現了 OAuth 2.0 協議,你應該使用合法的 HTTP 來訪問它。然而,我們有一個叫做 IdentityModel 的客戶端庫,它將協議交互封裝到了一個易於使用的 API 里面。
添加 IdentityModel NuGet 程序包到你的客戶端項目中。

IdentityModel 包含了一個用於 發現端點 的客戶端庫。這樣一來你只需要知道 IdentityServer 的基礎地址 —— 實際的端點地址可以從元數據中讀取:
// 從元數據中發現端口
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);
注意:從控制台中復制和粘貼訪問令牌到 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));
}
最終輸出看起來應該是這樣的:

注意:默認情況下訪問令牌將包含 scope 身份信息,生命周期(nbf 和 exp),客戶端 ID(client_id) 和 發行者名稱(iss)。
進一步實踐
當前演練目前主要關注的是成功的步驟:
- 客戶端可以請求令牌
- 客戶端可以使用令牌來訪問 API
你現在可以嘗試引發一些錯誤來學習系統的相關行為,比如:
- 嘗試在 IdentityServer 未運行時(unavailable)連接它
- 嘗試使用一個非法的客戶端id或密碼來請求令牌
- 嘗試在請求令牌的過程中請求一個非法的 scope
- 嘗試在 API 未運行時(unavailable)調用它
- 不向 API 發送令牌
- 配置 API 為需要不同於令牌中的 scope
上一篇:IdentityServer4 中文文檔 -8- (快速入門)設置和概覽
下一篇:IdentityServer4 中文文檔 -10- (快速入門)使用密碼保護API
