一.前言
本文已更新到 .NET Core 2.2
本文包括后續的Demo都會放在github:https://github.com/stulzq/IdentityServer4.Samples (QuickStart的幾個Demo隨着本系列的更新,目前為從官方Demo倉庫的拷貝,防止本文和Demo不匹配,因為官方Demo和文檔一直在更新,本系列更新速度可能會慢一步)。
這里特別說明一下:快速入門以及Topic系列為了保持到最新,目前幾乎都是翻譯的官方文檔(以往的不適合最新版本就換掉了),需要深入一點的請看實戰系列。
二.使用客戶端認證保護API
此示例介紹了使用IdentityServer保護API的最基本場景。
在這種情況下,我們將定義一個API和要訪問它的客戶端。 客戶端將在IdentityServer上請求訪問令牌,並使用它來訪問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)
四.定義API、Identity資源
在QuickstartIdentityServer
項目中添加一個Config.cs
文件:
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
文件中:
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
要配置IdentityServer以使用Scope和客戶端定義,您需要向ConfigureServices方法添加代碼。
Startup.cs
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的各種元數據信息。
首次啟動時,IdentityServer將為您創建一個開發人員簽名密鑰,它是一個名為tempkey.rsa的文件。 您不必將該文件檢入源代碼管理中,如果該文件不存在,將重新創建該文件。
七.添加API
在項目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和身份驗證中間件到管道。 這些將:
- 驗證傳入令牌以確保它來自受信任的頒發者
- 驗證令牌是否有效用於此API(也稱為 audience)
將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);
九.調用API
要將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)。
十.使用Postman調試
十一.項目所用代碼
github地址: https://github.com/stulzq/IdentityServer4.Samples/tree/master/Quickstarts/1_ClientCredentials