一,准備內容
IdentityServer4 是Asp.net core的一個中間件,用於添加符合OpenId Connect和OAuth2.0規范的終端到Asp.net Core應用。在這里簡單介紹一下Openid和OAuth2.0。
OpenId:用戶身份認證(Authentication )。當用戶(End User)在微信、Google等OpenId提供者(OpenID Provider)平台注冊賬戶時會產生一個身份標識,這個身份標識就是OpenId,當用戶登錄第三方應用(Relying Part)時如果Relying Part支持OpenId登錄,會生成一個帶有重定向地址的Url跳至OpenId Provider平台登錄界面,用戶登錄成功后,根據重定向地址帶着OpenId跳回Relying Part,標識着用戶身份認證成功,該用戶在OpenId Provider平台有注冊。Relying Part根據OpenId自動注冊賬戶,至此身份認證結束。有時Relying Part需要從Openid Provider那獲取該用戶的更多信息或資源,OpenId Provider需要對Relying Part的請求進行授權管理,這時就用要到OAuth2.0。
OAuth2.0:用戶訪問授權(Authorization)。OAuth2.0是一個JWT(Json Web Token ,Json格式Web令牌)解決方案。其最終目的是給用戶一個包含加密令牌的JSON字符串,這個令牌內包含授權信息,決定了該用戶可以訪問那些資源。OAuth2.0協議規定了4種取得令牌的方式,可以參考這篇文章OAuth2.0的四種方式。
Openid Connect:實際上就是將Openid與OAuth2.0結合起來,解決身份認證和身份授權的問題。
客戶端模式只對客戶端進行授權,不涉及到用戶信息。如果你的api需要提供到第三方應用,第三方應用自己做用戶授權,不需要用到你的用戶資源,就可以用客戶端模式,只對客戶端進行授權訪問api資源。
二,創建Asp.net Core 項目
微軟提供了一些針對IdentityServer4的項目模板,在命令行中輸入” dotnet new -i IdentityServer4.Templates“即可安裝,安裝好后可以看到當前已安裝的項目模板,其中有一個"is4empty",其實就是一個asp.net core 應用裝了IdentityServer4包。在命令行中輸入:dotnet new is4empty -n Projectname 就會根據這個模板生成一個新項目。下圖是我的項目,一個api客戶端、一個mvc客戶端,一個identityserver4服務端,其中Api客戶端是受保護的Api資源,Mvc客戶端是第三方客戶端,用於訪問被保護的Api客戶端,可以看成是任意后端程序。

- 配置IdentityServer服務器,如果是用的is4empty模板創建的項目,已經有一些簡單配置,后面我們慢慢深化
public void ConfigureServices(IServiceCollection services)
{
//添加IdentityServer
var builder = services.AddIdentityServer()
//身份信息授權資源
.AddInMemoryIdentityResources(Config.GetIdentityResources())
//API訪問授權資源
.AddInMemoryApiResources(Config.GetApis())
//添加客戶端
.AddInMemoryClients(Config.GetClients());
if (Environment.IsDevelopment())
{
builder.AddDeveloperSigningCredential();
}
else
{
throw new Exception("need to configure key material");
}
}
public void Configure(IApplicationBuilder app)
{
if (Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//使用IdentityServer中間件
app.UseIdentityServer();
}
為了能更好的查看調試日志,使用窗口調試,可以在Properties/launchSettings.json中可以更改監聽地址,默認為5000

啟動項目后使用瀏覽器打開:http://localhost:5000/.well-known/openid-configuration。可以看到identityserver4的discover說明。
三,配置IdentityServer4
1,添加ApiResource:修改IdentityServer項目的Config類的GetClients方法,添加一個api資源(ApiResource)。每個被保護的API項目必需有對應一個ApiResource,一個ApiResource可以有被多個API標識,客戶端請求令牌時根據ApiResource名稱決定是否有權限訪問這個API。
public static IEnumerable<ApiResource> GetApis()
{
return new ApiResource[] {
//secretapi:標識名稱,Secret Api:顯示名稱,可以自定義
new ApiResource("secretapi","Secret Api")
};
}
2,添加客戶端模式用戶:定義好ApiResouce后,再來添加一個客戶端,使得這個客戶端可以訪問secretapi這個資源。修改Config類中的GetClients方法,添加一個用戶用於支持客戶端模式的請求。
public static IEnumerable<Client> GetClients()
{
return new Client[] {
new Client()
{
//客戶端Id
ClientId="apiClientCd",
//客戶端密碼
ClientSecrets={new Secret("apiSecret".Sha256()) },
//客戶端授權類型,ClientCredentials:客戶端憑證方式
AllowedGrantTypes=GrantTypes.ClientCredentials,
//允許訪問的資源
AllowedScopes={
"secretapi"
}
}
};
}
四,配置API客戶端
1,配置API項目監聽端口和調試方式

2,配置Api項目認證
IdentityApi.Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddAuthentication("Bearer").AddJwtBearer(r => {
//認證地址
r.Authority = "http://localhost:5000";
//權限標識
r.Audience = "secretapi";
//是否必需HTTPS
r.RequireHttpsMetadata = false;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
//使用認證中間件
app.UseAuthentication();
app.UseMvcWithDefaultRoute();
}
3,添加接口:新建一個空的Api控制器(IdentityController),在這個控制器中添加一個Api:GetUserClaims
[ApiController]
public class IdentityController : ControllerBase
{
[HttpGet]
[Route("api/identity")]
[Microsoft.AspNetCore.Authorization.Authorize]
public object GetUserClaims()
{
return User.Claims.Select(r => new { r.Type, r.Value });
}
}
這時GetUserClaims這個Api是訪問不了的,用PostMan訪問時返回401未認證狀態

五,訪問受保護的Api
要訪問上面那個受保護的Api,分為2步,第一步從IdentityServer獲取token,第二步把這個token使用Bearer authorization 方式添加到Http請求頭。
1,在IdentityMvc項目訪問受保護的Api
IdentityMvc項目安裝一個Nuget包:IdentityModel,這個包對HttpClient對象有擴寫,封裝了一些IdentityServer的常用請求。修改IdentityServer的監聽端口為5002,使用窗口調試。
在IdentityMvc的HomeController.cs新增一個控制器GetData
public async Task<IActionResult> GetData()
{
var client = new HttpClient();
var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000");
if (disco.IsError)
return new JsonResult(new { err=disco.Error});
var token= await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest() {
//獲取Token的地址
Address = disco.TokenEndpoint,
//客戶端Id
ClientId = "apiClientCd",
//客戶端密碼
ClientSecret = "apiSecret",
//要訪問的api資源
Scope = "secretapi"
});
if (token.IsError)
return new JsonResult(new { err = token.Error });
client.SetBearerToken(token.AccessToken);
string data = await client.GetStringAsync("https://localhost:5001/api/identity");
JArray json = JArray.Parse(data);
return new JsonResult(json);
}
訪問https://localhost:5002/home/getdata可以看到已經成功返回數據

2,使用原生HTTP請求訪問受保護的Api
獲取access_token:直接打開http://localhost:5000/.well-known/openid-configuration,找到token_endpoint節點

使用PostMan對該節點發送如下Post請求獲取access_token

訪問被保護的Api
由於使用的是Bearer認證機制,所以添加一個名為Authorization的Http請求頭,請求頭的內容是字符串“Bearer”+空格+獲取到的Token:Bearer Token
下一篇:dentityServer4實現OAuth2.0之密碼模式.
