本文已更新到 .NET Core 2.2
本文包括後續的Demo都會放在github:https://github.com/stulzq/IdentityServer4.Samples (QuickStart的幾個Demo隨着本系列的更新,目前爲從官方Demo倉庫的拷貝,防止本文和Demo不匹配,由於官方Demo和文檔一直在更新,本系列更新速度可能會慢一步)。
這裏特別說明一下:快速入門以及Topic系列爲了保持到最新,目前幾乎都是翻譯的官方文檔(以往的不適合最新版本就換掉了),須要深刻一點的請看實戰系列。git
此示例介紹了使用IdentityServer保護API的最基本場景。github
在這種狀況下,咱們將定義一個API和要訪問它的客戶端。 客戶端將在IdentityServer上請求訪問令牌,並使用它來訪問API。api
建立一個名爲QuickstartIdentityServer
的ASP.NET Core Web 空項目(asp.net core 2.2),端口5000
建立一個名爲Api
的ASP.NET Core Web Api 項目(asp.net core 2.2),端口5001
建立一個名爲Client
的控制檯項目(.net core 2.2)瀏覽器
在QuickstartIdentityServer
項目中添加一個Config.cs
文件:app
public static class Config { public static IEnumerable<IdentityResource> GetIdentityResources() { return new IdentityResource[] { new IdentityResources.OpenId() }; } public static IEnumerable<ApiResource> GetApis() { return new List<ApiResource> { new ApiResource("api1", "My API") }; } public static IEnumerable<Client> GetClients() { return new List<Client> { new Client { ClientId = "client", // no interactive user, use the clientid/secret for authentication AllowedGrantTypes = GrantTypes.ClientCredentials, // secret for authentication ClientSecrets = { new Secret("secret".Sha256()) }, // scopes that client has access to AllowedScopes = { "api1" } } }; } }
對於這種狀況,客戶端將不具備交互式(人機交互)用戶,並將使用IdentityServer的客戶端模式進行身份驗證。 將如下代碼添加到Config.cs
文件中:asp.net
public static IEnumerable<Client> GetClients() { return new List<Client> { new Client { ClientId = "client", // no interactive user, use the clientid/secret for authentication AllowedGrantTypes = GrantTypes.ClientCredentials, // secret for authentication ClientSecrets = { new Secret("secret".Sha256()) }, // scopes that client has access to AllowedScopes = { "api1" } } }; }
要配置IdentityServer以使用Scope和客戶端定義,您須要向ConfigureServices方法添加代碼。ide
Startup.cs
post
public void ConfigureServices(IServiceCollection services) { var builder = services.AddIdentityServer() .AddDeveloperSigningCredential() .AddInMemoryIdentityResources(Config.GetIdentityResources()) .AddInMemoryApiResources(Config.GetApis()) .AddInMemoryClients(Config.GetClients()); // rest omitted } public void Configure(IApplicationBuilder app) { if (Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } // uncomment if you want to support static files //app.UseStaticFiles(); app.UseIdentityServer(); // uncomment, if you wan to add an MVC-based UI //app.UseMvcWithDefaultRoute(); }
運行此項目,打開瀏覽器訪問http://localhost:5000/.well-known/openid-configuration
你將會看到IdentityServer的各類元數據信息。ui
首次啓動時,IdentityServer將爲您建立一個開發人員簽名密鑰,它是一個名爲tempkey.rsa的文件。 您沒必要將該文件檢入源代碼管理中,若是該文件不存在,將從新建立該文件。.net
在項目Api
中添加一個Controller:IdentityController
[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 }); } }
最後一步是將身份驗證服務添加到DI和身份驗證中間件到管道。 這些將:
將Startup更新爲以下所示:
public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMvcCore() .AddAuthorization() .AddJsonFormatters(); services.AddAuthentication("Bearer") .AddJwtBearer("Bearer", options => { options.Authority = "http://localhost:5000"; options.RequireHttpsMetadata = false; options.Audience = "api1"; }); } public void Configure(IApplicationBuilder app) { app.UseAuthentication(); app.UseMvc(); } }
AddAuthentication
將身份認證服務添加到DI,並將「Bearer」配置爲默認方案。 AddJwtBearer
將 JWT 認證處理程序添加到DI中以供身份認證服務使用。 UseAuthentication
將身份認證中間件添加到管道中,所以將在每次調用API時自動執行身份驗證。
若是在瀏覽器訪問(http:// localhost:5001/identity),你會獲得HTTP 401的結果。 這意味着您的API須要憑據。
就是這樣,API如今受 IdentityServer 保護。
爲 "Client" 項目添加 Nuget 包:IdentityModel
IdentityModel 包括用於發現 IdentityServer 各個終結點(EndPoint)的客戶端庫。這樣您只須要知道 IdentityServer 的地址 - 能夠從元數據中讀取實際的各個終結點地址:
// discover endpoints from metadata var client = new HttpClient(); var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000"); if (disco.IsError) { Console.WriteLine(disco.Error); return; }
DiscoveryClient 已在最新版移除
接下來,您可使用從 IdentityServer 元數據獲取到的Token終結點請求令牌:
// request token var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest { Address = disco.TokenEndpoint, ClientId = "client", ClientSecret = "secret", Scope = "api1" }); if (tokenResponse.IsError) { Console.WriteLine(tokenResponse.Error); return; } Console.WriteLine(tokenResponse.Json);
要將Token發送到API,一般使用HTTP Authorization標頭。 這是使用SetBearerToken
擴展方法完成的:
// call 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)); }
輸出應以下所示:
默認狀況下,Token將包含有關 Scope,生命週期(nbf和exp),客戶端ID(client_id)和頒發者名稱(iss)的身份信息單元(Claim)。
github地址: https://github.com/stulzq/IdentityServer4.Samples/tree/master/Quickstarts/1_ClientCredentials