IdentityServer4-EF动态配置Client和对Claims授权(二)
原文:IdentityServer4-EF動態配置Client和對Claims授權(二)
本節介紹Client的ClientCredentials客戶端模式,先看下畫的草圖:
一、在Server上添加動態新增Client的API 接口。
為了方便測試,在Server服務端中先添加swagger,添加流程可參考:https://www.cnblogs.com/suxinlcq/p/6757556.html
?
在ValuesController控制器中注入ConfigurationDbContext上下文,此上下文可用來加載或配置IdentityServer4.EntityFramework的Client、身份信息、API資源信息或CORS數據等。
在ValuesController中實添加以下代碼:
private ConfigurationDbContext _context;public ValuesController(ConfigurationDbContext context){_context = context;}添加動態新增Client的API接口:
[HttpPost]public IActionResult Post([FromBody] IdentityServer4.EntityFramework.Entities.Client client){var res = _context.Clients.Add(client);if(_context.SaveChanges() >0)return Ok(true);elsereturn Ok(false);}控制器代碼如下:
?
二、對Server上的API進行保護
(1)安裝IdentityServer4.AccessTokenValidation包
(2)在startup.cs中ConfigureServices方法添加如下代碼:
//protect API services.AddMvcCore().AddAuthorization().AddJsonFormatters();services.AddAuthentication("Bearer").AddIdentityServerAuthentication(options =>{options.Authority = "http://localhost:5000";options.RequireHttpsMetadata = false;options.ApiName = "api1";});AddAuthentication把Bearer配置成默認模式,將身份認證服務添加到DI中。
AddIdentityServerAuthentication把IdentityServer的access token添加到DI中,供身份認證服務使用。
(3)在startup.cs中Configure方法添加如下代碼:
public void Configure(IApplicationBuilder app, IHostingEnvironment env){//if (env.IsDevelopment())//{// app.UseDeveloperExceptionPage();//}//AddSwagger app.UseSwagger();app.UseSwaggerUI(c =>{c.SwaggerEndpoint("/swagger/v1/swagger.json", "Server接口文檔");});InitializeDatabase(app);app.UseAuthentication();app.UseIdentityServer();app.UseMvc();}UseAuthentication將身份驗證中間件添加到管道中,以便在每次調用主機時自動執行身份驗證。
(4)在ValuesController控制器中添加[Authorize]
?
(5)在項目屬性->調試 中,啟動瀏覽器,并設成swagger,如圖:
(6)啟動項目,并調用第一個Get接口。
顯示Unauthorized(未授權),證明[Authorize]起作用了。
?
三、搭建Client客戶端
(1)新建一個控制臺程序,安裝IdentityModel包。
(2)添加類IDSHelper.cs,添加客戶端請求API接口代碼。
public class IDSHelper{public static async Task MainAsync(){try{DiscoveryResponse disco = await DiscoveryClient.GetAsync("http://localhost:5000");if (disco.IsError){Console.WriteLine(disco.Error);return;}TokenClient 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 client = new HttpClient();client.SetBearerToken(tokenResponse.AccessToken);var response = await client.GetAsync("http://localhost:5000/api/values/");if (!response.IsSuccessStatusCode){Console.WriteLine(response.StatusCode);}else{var content = await response.Content.ReadAsStringAsync();Console.WriteLine(content);}}catch (Exception ex){}} }(3)修改Program.cs代碼,如下:
class Program{static void Main(string[] args)=> IDSHelper.MainAsync().GetAwaiter().GetResult();}(4)按Ctrl+F5,可以獲取到access token和接口返回值
復制token,用postman調用,成功獲取到了接口返回值。
?
四、測試動態新增Client接口
安裝IdentityServer4包。
安裝IdentityServer4.EntityFramework包。
在IDSHelper.cs類中添加Post方法:
public static async Task Post(){try{DiscoveryResponse disco = await DiscoveryClient.GetAsync("http://localhost:5000");if (disco.IsError){Console.WriteLine(disco.Error);return;}TokenClient 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 client = new HttpClient();client.SetBearerToken(tokenResponse.AccessToken);Client c1 = new Client{ClientId = "Test",AllowedGrantTypes = GrantTypes.ClientCredentials,ClientSecrets ={new Secret("secret".Sha256())},AllowedScopes = { "api1" }};string strJson = JsonConvert.SerializeObject(c1 .ToEntity());HttpContent content = new StringContent(strJson);content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");//由HttpClient發出Post請求Task<HttpResponseMessage> response = client.PostAsync("http://localhost:5000/api/values/", content);if (response.Result.StatusCode != System.Net.HttpStatusCode.OK){Console.WriteLine(response.Result.StatusCode);}else{Console.WriteLine(response.Result.Content.ReadAsStringAsync().Result);}}catch (Exception ex){}}順便把main中改成對Post調用:
static void Main(string[] args)=> IDSHelper.Post().GetAwaiter().GetResult();按Ctrl+F5,調用新增Client的接口,并成功返回true。
同時可以在數據庫中的Client表找到相關記錄。需要注意的是,不能添加相同Client ID的Client。
?
五、在Client中添加Claim信息,并在API接口中對Claim信息進行驗證。
關于Claim的介紹可以看這篇文章:http://www.cnblogs.com/stulzq/p/8726002.html
這里把Claim簡單當做用戶的身份信息使用,修改Post方法里面的Client:
Client c1 = new Client{ClientId = "superAdmin",AllowedGrantTypes = GrantTypes.ClientCredentials,ClientSecrets ={new Secret("secret".Sha256())},AllowedScopes = { "api1" },Claims = new List<Claim>{new Claim(JwtClaimTypes.Role, "admin")}};可以看出,Claims為List,可以是很多個角色,這里只添加一個。
Ctrl+F5,運行成功添加superAdmin Client。
?
現在,需要對Server服務端的新增Client接口進行Claim身份驗證,添加如下代碼:
? ?[Authorize(Roles ="admin")]
然后再客戶端修改授權的賬號為superadmin。
TokenClient tokenClient = new TokenClient(disco.TokenEndpoint, "superAdmin", "secret");
Ctrl+F5運行
問題出現了,返回了Forbidden,沒有權限進行訪問。
這時候我們上官網查閱了資料,發現在添加Client的Claim時候,IdentityServer EntityFramework會為Claim的role添加一個默認前綴,為client_。所以,實際上它為client_role。
而服務端只能對role進行驗證。
此時我們需要把Claim的默認前綴去掉,設置為空ClientClaimsPrefix = "" 。
?
去掉Server的Role驗證,添加形如下面代碼的Client。
Client c1 = new Client{ClientId = "adminClient",AllowedGrantTypes = GrantTypes.ClientCredentials,ClientSecrets ={new Secret("secret".Sha256())},AllowedScopes = { "api1" },Claims = new List<Claim>{new Claim(JwtClaimTypes.Role, "admin")},ClientClaimsPrefix = "" //把client_ 前綴去掉};?Ctrl+F5,運行成功添加adminClient Client,這次的是Role為admin。
然后重新再Server服務端加上[Authorize(Roles ="admin")]
同時修改驗證賬號為adminClient。
TokenClient tokenClient = new TokenClient(disco.TokenEndpoint, "adminClient", "secret");
最后運行程序,成功地在[Authorize(Roles ="admin")]權限下訪問并新增了Client。
?
六、需要注意的問題
(1)新增Client到數據庫時候,這里需要接收IdentityServer4.EntityFramework.Entities.Client
而不是IdentityServer4.Models.Client,否則API接口在接收和轉化Client模型的時候會報錯。
(2)此外,本節介紹的Client的AllowedGrantTypes 都為 GrantTypes.ClientCredentials,相應的,客戶端請求是,需要用RequestClientCredentialsAsync方法。
最后再次提下,ClientCredentials模式的適用場景:用于和用戶無關,服務與服務之間直接交互訪問資源。
?
Server服務端源碼地址:https://github.com/Bingjian-Zhu/Server
Client客戶端源碼地址:https://github.com/Bingjian-Zhu/Client
文中如有錯漏,歡迎指正。
posted on 2018-12-30 13:32 NET未來之路 閱讀(...) 評論(...) 編輯 收藏轉載于:https://www.cnblogs.com/lonelyxmas/p/10199198.html
總結
以上是生活随笔為你收集整理的IdentityServer4-EF动态配置Client和对Claims授权(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: dp凸优化/wqs二分学习笔记(洛谷43
- 下一篇: MariaDB 主从同步与热备(14)