OAuth 2.0資源(web api)全部者密碼受權,容許客戶端(Client項目)向令牌服務(IdentityServer項目)發送用戶名和密碼,並獲取表明該用戶的訪問令牌。在官方文檔中講到:規範一般建議不要使用「資源全部者密碼受權」。當用戶進行身份驗證並請求訪問令牌時,使用一個交互式OpenID Connect流程一般要好得多(下篇再瞭解)。html
本篇介紹「資源全部者密碼受權」是由於這種受權容許咱們快速啓動IdentityServer。開源地址:Github git
下面示例與官方示例有點區別,該示例使用了Identity密碼保護API。關於asp.net core Identity的瞭解實現,查看以前章節或官方文檔。示例中分別是IdentityServer令牌項目、 API資源項目、 Client訪問項目。與上篇相比同樣,仍是三個項目,區別在於:github
(1) IdentityServer令牌項目換成了含有asp.net core Identity的MVC項目。web
(2) API資源項目沒有變更。數據庫
(3) Client訪問項目使用了用戶名和密碼訪問受保護的API。api
IdentityServer令牌項目是包含了 Identity功能(安裝:Install-Package IdentityServer4),在項目中,添加了Config.cs類和Startup.cs中加入了IdentityServer的啓動配置。下面是MVC項目目錄結構:asp.net
(1) 添加用戶ide
IdentityServer類庫中自帶TestUser測試類,是DTO數據傳輸對象,存儲用戶及其聲明(claims)。TestUser是用於測試中的內存(In-memory)用戶對象。在正式環境下,獲取數據庫中的用戶表(User),須要結合IdentityServer的IResourceOwnerPasswordValidator接口(再也不本篇講述中)。 下面經過在config.cs類中添加GetUsers方法獲取用戶密碼,存儲在TestUser數據傳輸對象中。測試
/// <summary> ///獲取用戶,這些用戶能夠訪問受密碼保護的API /// </summary> /// <param name="provider"></param> /// <returns></returns> public static List<TestUser> GetUsers(ServiceProvider provider) { var webAppIdentityDemoUser = provider.GetRequiredService<UserManager<WebAppIdentityDemoUser>>(); IList<WebAppIdentityDemoUser> users = null; //獲取Identity的User表用戶,條件是屬於Administrator角色的用戶 users = webAppIdentityDemoUser.GetUsersInRoleAsync("Administrator").Result; List<TestUser> testUserList = new List<TestUser>(); foreach (WebAppIdentityDemoUser user in users) { testUserList.Add(new TestUser() { SubjectId = user.Id.ToString(), Username = user.UserName, Password = user.PasswordHash }); } return testUserList; }
(2) 而後在Startup類的ConfigureServices方法中使用IdentityServer注入測試用戶:ui
ServiceProvider provider = services.BuildServiceProvider(); var builder = services.AddIdentityServer() .AddInMemoryIdentityResources(Config.GetIdentityResources()) .AddInMemoryApiResources(Config.GetApis()) .AddInMemoryClients(Config.GetClients()) .AddTestUsers(Config.GetUsers(provider));
(3) 定義客戶端, 使用密碼授予訪問此API(資源範圍:api1)
在config.cs類中,定義客戶端,經過修改AllowedGrantTypes枚舉來簡單地向現有客戶端添加對受權類型的支持, 將如下代碼添加到客戶端配置中, 裏面支持二個Client受權類型,分別是ClientCredentials使用憑證來訪問令牌和ResourceOwnerPassword 使用密碼來訪問令牌。
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" } }, // resource owner password grant client new Client { ClientId = "ro.client", AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, ClientSecrets = { new Secret("secret".Sha256()) }, AllowedScopes = { "api1" } } }; }
該Client項目相似於上篇介紹的Client項目,該項目名爲ResourceOwnerClient, 該Client將收集用戶名和密碼,並在令牌請求期間,將其發送到IdentityServer令牌服務(WebAppIdentityDemo項目)
// request token 請求令牌 var tokenResponse = await client.RequestPasswordTokenAsync(new PasswordTokenRequest { Address = disco.TokenEndpoint, ClientId = "ro.client", ClientSecret = "secret", UserName = "924964690@qq.com", Password = "AQAAAAEAACcQAAAAEH4Xhui5BByq6d8VS5Z+S2o2SnlkyrP5pN9CmMpgJ4QiIVrt7lBLzDlEWa6AdlpxpA==", Scope = "api1" }); if (tokenResponse.IsError) { Console.WriteLine(tokenResponse.Error); return; } Console.WriteLine(tokenResponse.Json); Console.WriteLine("\n\n");
最後測試,先啓動WebAppIdentityDemo項目程序,再啓動API程序,最後啓動Client客戶端來訪問API,經過下圖能夠了解到:(1)客戶端請求使用「用戶名和和密碼」訪問令牌(token)成功, (2) 客戶端使用令牌(AccessToken)來訪問受密碼保護的web API接口成功。
參考文獻