一 使用緣由
最近寫微服務的blog,研讀了o’reilly出的 《building Microservices With Asp.net Core》,其中使用的微服務分布式權限組件是microsoft.aspnetcore.authentication.jwtbearer,那最近identityserver4這么流行,就決定替換掉它。
二 開始
1 認證流程:
2 開發
認證服務器:
(1) 首先一個空的asp.net core 項目,在nuget包中安裝identityserver4 包
(2) 項目組織,會增加Config.cs的文件。
相關代碼:
using IdentityServer4.Models; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Walt.Freamwork.Sec { public class Config { public static IEnumerable<ApiResource> GetApiResources() { 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" } } }; } } }
public void ConfigureServices(IServiceCollection services) { // configure identity server with in-memory stores, keys, clients and resources services.AddIdentityServer() .AddDeveloperSigningCredential() .AddInMemoryApiResources(Config.GetApiResources()) .AddInMemoryClients(Config.GetClients()); services.AddMvc(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseIdentityServer(); app.UseMvc((route) => { route.MapRoute("default", "{controller=Home}/{action=Index}/{id?}"); }); }
被請求資源服務器
(1)為webapi增加identityserver4.accesstokenvalidation包
(2) 配置
public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.AddAuthorization(); services.AddAuthentication("Bearer") .AddIdentityServerAuthentication(options => { options.Authority = "http://localhost:64433"; //授權服務器 options.RequireHttpsMetadata = false; options.ApiName = "api1"; }); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { var log= LoggerFac.CreateLogger<Startup>(); log.LogInformation("infomation"); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseHsts(); } app.UseAuthentication(); //使用認證 app.UseHttpsRedirection(); app.UseMvc(); }
客戶端:從代碼中可以看出,分兩步,第一步獲取token
,第二部根據token去訪問需要的服務。
using System; using System.Net.Http; using IdentityModel.Client; using IdentityServer4; using Newtonsoft.Json.Linq; namespace Walt.Freamwork.Sec.Client { class Program { static void Main(string[] args) { var disco = DiscoveryClient.GetAsync("http://localhost:64433/").Result; if (disco.IsError) { Console.WriteLine(disco.Error); return; } // request token var tokenClient = new TokenClient(disco.TokenEndpoint, "client", "secret"); var tokenResponse = tokenClient.RequestClientCredentialsAsync("api1").Result; if (tokenResponse.IsError) { Console.WriteLine(tokenResponse.Error); return; } Console.WriteLine(tokenResponse.Json); // call api var client = new HttpClient(); client.SetBearerToken(tokenResponse.AccessToken); var response = client.GetAsync("http://localhost:50403/api/identity").Result; if (!response.IsSuccessStatusCode) { Console.WriteLine(response.StatusCode); } else { var content = response.Content.ReadAsStringAsync().Result; Console.WriteLine(JArray.Parse(content)); } Console.ReadKey(); } } }
運行情況:咱們為webapi定義一個api
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Walt.Freamwork.Sec { [Route("api/[controller]")] [ApiController] [Authorize] public class IdentityController : ControllerBase { [HttpGet] public IActionResult Get() { return new JsonResult(from c in User.Claims select new { c.Type, c.Value }); } } }
如果不帶token
using System; using System.Net.Http; using IdentityModel.Client; using IdentityServer4; using Newtonsoft.Json.Linq; namespace Walt.Freamwork.Sec.Client { class Program { static void Main(string[] args) { var disco = DiscoveryClient.GetAsync("http://localhost:64433/").Result; if (disco.IsError) { Console.WriteLine(disco.Error); return; } // request token var tokenClient = new TokenClient(disco.TokenEndpoint, "client", "secret"); var tokenResponse = tokenClient.RequestClientCredentialsAsync("api1").Result; if (tokenResponse.IsError) { Console.WriteLine(tokenResponse.Error); return; } Console.WriteLine(tokenResponse.Json); // call api var client = new HttpClient(); // client.SetBearerToken(tokenResponse.AccessToken); 這塊注釋掉了 var response = client.GetAsync("http://localhost:50403/api/identity").Result; if (!response.IsSuccessStatusCode) { Console.WriteLine(response.StatusCode); } else { var content = response.Content.ReadAsStringAsync().Result; Console.WriteLine(JArray.Parse(content)); } Console.ReadKey(); } } }
總結:本實例使用的是聲明的方式認證,也可以使用用戶名密碼。 identityserver4是個功能強大但是使用很簡潔的一個認證框架,
也支持OAUTH為外部認證提供支持,這里就不討論了。




