Identity Server4學習系列四之使用者名稱密碼獲得訪問令牌 Identity Server4學習系列三
阿新 • • 發佈:2018-12-15
1、簡介
Identity Server4支援使用者名稱密碼模式,允許呼叫客戶端使用使用者名稱密碼來獲得訪問Api資源(遵循Auth 2.0協議)的Access Token,MS可能考慮相容老的系統,實現了這個功能,但是不建議這麼做.
2、實戰一服務端配置
接著Identity Server4學習系列三的基礎上,直接擴充套件裡面的專案程式碼,讓服務端同時支援金鑰認證和使用者名稱密碼認證
第一步:擴充套件ThirdClients類,如下:
/// <summary> /// 配置可以訪問IdentityServer4 保護的Api資源模型的第三方客戶端/// 配置客戶端訪問的金鑰 /// </summary> public class ThirdClients { public static IEnumerable<Client> GetClients() { return new List<Client>() { new Client() { //客戶端的唯一Id,客戶端需要指定該ClientId才能訪問 ClientId = $"client", //no interactive user, use the clientid/secret for authentication //使用客戶端金鑰進行認證 AllowedGrantTypes = GrantTypes.ClientCredentials, // 認證金鑰,客戶端必須使用secret金鑰才能成功訪問 ClientSecrets = {//用Sha256對"secret"進行加密 new Secret("secret".Sha256()) }, // scopes that client has access to //如果客戶端的金鑰認證成功,限定該金鑰可以訪問的Api範圍 AllowedScopes = { "api1" } }, //新增支援使用者名稱密碼模式訪問的客戶端型別 new Client() { ClientId = "userPwd.client", AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, ClientSecrets = { new Secret("secret".Sha256()) }, AllowedScopes = { "api1" } } }; } /// <summary> /// 配置可以訪問IdentityServer4 保護的Api資源模型的第三方客戶端 /// 使用使用者名稱密碼模式 /// </summary> /// <returns></returns> public static List<TestUser> GetUsers() { return new List<TestUser>() { new TestUser() { SubjectId = "1", Username = "alice", Password = "password" } }; } }
第二步:註冊TestUser到Identity Server4,修改StartUp檔案如下:
public class Startup { // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { //優雅的鏈式程式設計 //注入Identity Server4服務到DI容器中 services.AddIdentityServer() //注入臨時簽名憑據到DI容器,後期可用簽名證書的金鑰替換,用於生成零時金鑰 .AddDeveloperSigningCredential() //注入需要受Identity Server4保護的Api資源添注入到DI容器中 -記憶體級別 .AddInMemoryApiResources(Apis.GetApiResources()) //注入需要訪問受Identity Server4保護的Api資源的客戶端(金鑰模式)注入到DI容器中 -記憶體級別 .AddInMemoryClients(ThirdClients.GetClients()) //注入需要訪問受Identity Server4保護的Api資源的客戶端(使用者名稱密碼訪問模式)注入到DI容器中 -記憶體級別 .AddTestUsers(ThirdClients.GetUsers()); //注入基本的MVC服務 services.AddMvcCore() //注入MVC的認證服務,對應控制器的Authorize特性 .AddAuthorization() //注入MVC格式化程式,對應JsonResult等等的格式化操作,主要用於控制器返回值的格式化操作 .AddJsonFormatters(); //注入身份認證服務,設定Bearer為預設方案 services.AddAuthentication("Bearer") //注入並配置Bearer為預設方案的基本引數 .AddIdentityServerAuthentication(options => { //設定令牌的釋出者 options.Authority = "http://localhost:5000"; //設定Https options.RequireHttpsMetadata = false; //需要認證的api資源名稱 options.ApiName = "api1"; }); } // 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()) { //從管道中捕獲同步和非同步System.Exception例項並生成HTML錯誤響應。 app.UseDeveloperExceptionPage(); } //將IdentityServer 4服務注入到管道模型中(對應上面的IdentityServer 4服務的配置) app.UseIdentityServer(); //將認證服務通過Microsoft.AspNetCore.Authentication.AuthenticationMiddleware中介軟體 //注入到管道模型中(對應上面認證服務的配置) app.UseAuthentication(); //將mvc新增到Microsoft.AspNetCore.Builder.IApplicationBuilder請求執行中(對應上的MVC配置) app.UseMvc(); } }
ok,到這一步,Identity Server4服務端配置完成!
3、實戰一客戶端發起呼叫
呼叫程式碼如下:
class Program { static void Main(string[] args) { Request(); Console.ReadKey(); } async static void Request() { //請求Identity Server4服務 var disco = await DiscoveryClient.GetAsync("http://localhost:5000"); if (disco.IsError) { Console.WriteLine(disco.Error); return; } var tokenClient = new TokenClient(disco.TokenEndpoint, "userPwd.client", "secret"); var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync("alice", "password", "api1"); if (tokenResponse.IsError) { Console.WriteLine(tokenResponse.Error); return; } //通過Identity Server4的認證過後,拿到AccessToken var client = new HttpClient(); client.SetBearerToken(tokenResponse.AccessToken); var response = await client.GetAsync("http://localhost:5000/identity"); if (!response.IsSuccessStatusCode) { Console.WriteLine(response.StatusCode); } else { //認證成功,輸出Identity控制器的返回值 var content = await response.Content.ReadAsStringAsync(); Console.WriteLine(JArray.Parse(content)); } Console.WriteLine(tokenResponse.Json); Console.WriteLine("\n\n"); } }
ok,使用使用者名稱加金鑰模式,訪問Api成功拿到Api返回值,注意金鑰任然需要給,因為這個金鑰是用與給Token加密的,而使用者名稱和密碼無非是繼續加一了一層認證,如果金鑰認證成功,必須進行使用者名稱和密碼的認證,兩者必須同時認證成功,才能成功的發起Api的呼叫.
使用者名稱和密碼必須和服務端給定的一致,否則客戶端會報這個錯:
無效的授權.
至此,使用者名稱密碼加金鑰模式介紹完畢!