.Net Core 3.0 IdentityServer4 快速入門 —— resource owner password credentials(密碼模式) 一、前言 OAuth2.0預設有四種授權模式(GrantType): 1)授權碼模式 2)簡化模式 3)密碼模式(resource owne ...
.Net Core 3.0 IdentityServer4 快速入門
—— resource owner password credentials(密碼模式)
一、前言
OAuth2.0預設有四種授權模式(GrantType):
1)授權碼模式
2)簡化模式
3)密碼模式(resource owner password credentials)
4)客戶端模式(client_credentials)
上一小節 接受了 客戶端模式 ,本小節將介紹 密碼模式,OAuth2.0資源所有者密碼授權功能允許客戶端將用戶名和密碼發送到授權伺服器,並獲得該用戶的訪問令牌
認證步驟:
1)用戶將用戶名和密碼提供給客戶端
2)客戶端再將用戶名和密碼發送給授權伺服器(Id4)請求令牌
3)授權伺服器(Id4)驗證用戶的有效性,返回給客戶端令牌
4)Api資源收到第一個(首次)請求之後,會到授權伺服器(Id4)獲取公鑰,然後用公鑰驗證Token是否合法,如果合法將進行後面的有效性驗證,後面的請求都會用首次請求的公鑰來驗證(jwt去中心化驗證的思想)
Resource Owner 其實就是User,密碼模式相較於客戶端模式,多了一個參與者,就是User,通過User的用戶名和密碼向Identity Server 申請訪問令牌,這種模式下要求客戶端不得存儲密碼,但我們並不能確保客戶端是否存儲了密碼,所以該模式僅僅適用於受信任的客戶端。因此該模式不推薦使用
二、創建授權伺服器
1)安裝Id4
2)創建一個Config類模擬配置要保護的資源和可以訪問的api客戶端伺服器
1 using IdentityServer4; 2 using IdentityServer4.Models; 3 using IdentityServer4.Test; 4 using System.Collections.Generic; 5 6 namespace IdentityServer02 7 { 8 public static class Config 9 { 10 /// <summary> 11 /// 需要保護的api資源 12 /// </summary> 13 public static IEnumerable<ApiResource> Apis => 14 new List<ApiResource> 15 { 16 new ApiResource("api1","My Api") 17 }; 18 public static IEnumerable<Client> Clients => 19 new List<Client> 20 { 21 //客戶端 22 new Client 23 { 24 ClientId="client", 25 ClientSecrets={ new Secret("aju".Sha256())}, 26 AllowedGrantTypes=GrantTypes.ResourceOwnerPassword, 27 //如果要獲取refresh_tokens ,必須在scopes中加上OfflineAccess 28 AllowedScopes={ "api1", IdentityServerConstants.StandardScopes.OfflineAccess}, 29 AllowOfflineAccess=true 30 } 31 }; 32 33 public static List<TestUser> Users = new List<TestUser> 34 { 35 new TestUser 36 { 37 SubjectId="001", 38 Password="Aju_001", 39 Username="Aju_001" 40 }, 41 new TestUser 42 { 43 SubjectId="002", 44 Password="Aju_002", 45 Username="Aju_002" 46 } 47 }; 48 } 49 }
與客戶端模式不一致的地方就在於(AllowedGrantTypes=GrantTypes.ResourceOwnerPassword)此處設置為資源所有者(密碼模式)
3)配置StartUp
1 using Microsoft.AspNetCore.Builder; 2 using Microsoft.AspNetCore.Hosting; 3 using Microsoft.Extensions.DependencyInjection; 4 using Microsoft.Extensions.Hosting; 5 6 namespace IdentityServer02 7 { 8 public class Startup 9 { 10 // This method gets called by the runtime. Use this method to add services to the container. 11 // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 12 public void ConfigureServices(IServiceCollection services) 13 { 14 var builder = services.AddIdentityServer() 15 .AddInMemoryApiResources(Config.Apis) 16 .AddInMemoryClients(Config.Clients) 17 .AddTestUsers(Config.Users);19 builder.AddDeveloperSigningCredential(); 20 } 21 22 // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 23 public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 24 { 25 if (env.IsDevelopment()) 26 { 27 app.UseDeveloperExceptionPage(); 28 } 29 // app.UseRouting(); 30 app.UseIdentityServer(); 31 } 32 } 33 }
5)驗證配置是否成功
在瀏覽器中輸入(http://localhost:5000/.well-known/openid-configuration)看到如下發現文檔算是成功的
三、創建Api資源
1)步驟如創建授權服務的1)
2)安裝包
3)創建一個受保護的ApiController
1 using Microsoft.AspNetCore.Authorization; 2 using Microsoft.AspNetCore.Mvc; 3 using System.Linq; 4 5 namespace Api02.Controllers 6 { 7 [Route("Api")] 8 [Authorize] 9 public class ApiController : ControllerBase 10 { 11 public IActionResult Get() 12 { 13 return new JsonResult(from c in User.Claims select new { c.Type, c.Value }); 14 } 15 } 16 }
4)配置StartUp
1 using Microsoft.AspNetCore.Builder; 2 using Microsoft.AspNetCore.Hosting; 3 using Microsoft.Extensions.Configuration; 4 using Microsoft.Extensions.DependencyInjection; 5 using Microsoft.Extensions.Hosting; 6 7 namespace Api02 8 { 9 public class Startup 10 { 11 public Startup(IConfiguration configuration) 12 { 13 Configuration = configuration; 14 } 15 16 public IConfiguration Configuration { get; } 17 18 // This method gets called by the runtime. Use this method to add services to the container. 19 public void ConfigureServices(IServiceCollection services) 20 { 21 services.AddControllers(); 22 services.AddAuthentication("Bearer").AddJwtBearer("Bearer", options => 23 { 24 options.Authority = "http://localhost:5000"; 25 options.RequireHttpsMetadata = false; 26 options.Audience = "api1"; 27 }); 28 } 29 30 // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 31 public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 32 { 33 if (env.IsDevelopment()) 34 { 35 app.UseDeveloperExceptionPage(); 36 } 37 38 app.UseRouting(); 39 40 app.UseAuthentication();//認證 41 app.UseAuthorization();//授權 42 43 44 app.UseEndpoints(endpoints => 45 { 46 endpoints.MapControllers(); 47 }); 48 } 49 } 50 }
四、創建客戶端(控制台 模擬客戶端)
1 using IdentityModel.Client; 2 using Newtonsoft.Json.Linq; 3 using System; 4 using System.Net.Http; 5 using System.Threading.Tasks; 6 7 namespace Client02 8 { 9 class Program 10 { 11 static async Task Main(string[] args) 12 { 13 // Console.WriteLine("Hello World!"); 14 var client = new HttpClient(); 15 var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000"); 16 if (disco.IsError) 17 { 18 Console.WriteLine(disco.Error); 19 return; 20 } 21 var tokenResponse = await client.RequestPasswordTokenAsync( 22 new PasswordTokenRequest 23 { 24 Address = disco.TokenEndpoint, 25 ClientId = "client", 26 ClientSecret = "aju", 27 Scope = "api1 offline_access", 28 UserName = "Aju", 29 Password = "Aju_password" 30 }); 31 if (tokenResponse.IsError) 32 { 33 Console.WriteLine(tokenResponse.Error); 34 return; 35 } 36 Console.WriteLine(tokenResponse.Json); 37 Console.WriteLine("\n\n"); 38 //call api 39 var apiClient = new HttpClient(); 40 apiClient.SetBearerToken(tokenResponse.AccessToken); 41 var response = await apiClient.GetAsync("http://localhost:5001/api"); 42 if (!response.IsSuccessStatusCode) 43 { 44 Console.WriteLine(response.StatusCode); 45 } 46 else 47 { 48 var content = await response.Content.ReadAsStringAsync(); 49 Console.WriteLine(JArray.Parse(content)); 50 } 51 Console.ReadLine(); 52 } 53 } 54 }
五、驗證
1)直接獲取Api資源
出現了401未授權提示,這就說明我們的Api需要授權
2)運行客戶端訪問Api資源
六、自定義用戶驗證
在創建授權伺服器的時候我們在Config中預設模擬(寫死)兩個用戶,這顯得有點不太人性化,那我們就來自定義驗證用戶信息
1)創建 自定義 驗證 類 ResourceOwnerValidator
1 using IdentityModel; 2 using IdentityServer4.Models; 3 using IdentityServer4.Validation; 4 using System.Threading.Tasks; 5 6 namespace IdentityServer02 7 { 8 public class ResourceOwnerValidator : IResourceOwnerPasswordValidator 9 { 10 public Task ValidateAsync(ResourceOwnerPasswordValidationContext context) 11 { 12 if (context.UserName == "Aju" && context.Password == "Aju_password") 13 { 14 context.Result = new GrantValidationResult( 15 subject: context.UserName, 16 authenticationMethod: OidcConstants.AuthenticationMethods.Password); 17 } 18 else 19 { 20 context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "無效的秘鑰"); 21 } 22 return Task.FromResult(""); 23 } 24 } 25 }
2)在授權伺服器StartUp配置類中,修改如下:
3)在客戶端中將 用戶名 和 密碼 修改成 我們在自定義 用戶 驗證類 中寫的用戶名和密碼,進行測試
七、通過refresh_token 獲取 Token
1)refresh_token
獲取請求授權後會返回 access_token、expire_in、refresh_token 等內容,每當access_token 失效後用戶需要重新授權,但是有了refresh_token後,客戶端(Client)檢測到Token失效後可以直接通過refresh_token向授權伺服器申請新的token
八、參考文獻
http://docs.identityserver.io/en/latest/index.html
如果對您有幫助,請點個推薦(讓更多需要的人看到哦)