git地址:https://github.com/yizhaoxian/CoreIdentityServer4Demo.githtml
2.一、《IdentityServer4 (1) 客戶端受權模式(Client Credentials)》
2.二、《IdentityServer4 (2) 密碼受權(Resource Owner Password)》
2.三、《IdentityServer4 (3) 受權碼模式(Authorization Code)》
2.四、《IdentityServer4 (4) 靜默刷新(Implicit)》
2.五、《IdentityServer4 (5) 混合模式(Hybrid)》git
IdentityServer4 中文文檔 http://www.identityserver.com.cn/
IdentityServer4 英文文檔 https://identityserver4.readthedocs.io/en/latest/github
此文章是在上一篇文章的基礎上繼續修改的,基礎代碼請查看上一篇文章《IdentityServer4(1)客戶端受權模式》api
密碼受權模式,容許一個客戶端發送用戶名和密碼到令牌服務並得到一個表示該用戶的訪問令牌(AccessToken),這裏多了一個概念就是【用戶】,帳號密碼須要用戶提供給客戶端緩存
new Client { // 客戶端ID 這個很重要 ClientId = "client pwd", //資源全部者密碼受權客戶端定義 AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, // 用於認證的密碼 ClientSecrets = { new Secret("secret".Sha256()) }, // 客戶端有權訪問的範圍(Scopes) AllowedScopes = { "api1", IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, IdentityServerConstants.StandardScopes.Address, IdentityServerConstants.StandardScopes.Email, IdentityServerConstants.StandardScopes.Phone } }
新建一個類 TestUsers.csasync
public class TestUsers { public static List<TestUser> Users { get { var address = new { street_address = "ChaoYang", locality = "BeiJing", postal_code = 10010, country = "China" }; return new List<TestUser> { new TestUser { SubjectId = "818727", Username = "alice", Password = "alice", Claims = { new Claim(JwtClaimTypes.Name, "TestUser.Alice Smith"), new Claim(JwtClaimTypes.GivenName, "TestUser.Alice"), new Claim(JwtClaimTypes.FamilyName, "TestUser.Smith"), new Claim(JwtClaimTypes.PhoneNumber, "TestUser.13812345678"), new Claim(JwtClaimTypes.Email, "TestUser.AliceSmith@email.com"), new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean), new Claim(JwtClaimTypes.WebSite, "TestUser.http://alice.com"), new Claim(JwtClaimTypes.Address, JsonConvert.SerializeObject(address), IdentityServerConstants.ClaimValueTypes.Json) } }, new TestUser { SubjectId = "88421113", Username = "bob", Password = "bob", Claims = { new Claim(JwtClaimTypes.Name, "Bob Smith"), new Claim(JwtClaimTypes.GivenName, "Bob"), new Claim(JwtClaimTypes.FamilyName, "Smith"), new Claim(JwtClaimTypes.Email, "BobSmith@email.com"), new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean), new Claim(JwtClaimTypes.WebSite, "http://bob.com"), new Claim(JwtClaimTypes.Address, JsonConvert.SerializeObject(address), IdentityServerConstants.ClaimValueTypes.Json) } } }; } } }
StartUp.cs 添加測試用戶和用戶認證信息ide
public void ConfigureServices(IServiceCollection services) { services.AddIdentityServer() .AddDeveloperSigningCredential() //添加測試用戶 .AddTestUsers(TestUsers.Users) //添加用戶認證信息 .AddInMemoryIdentityResources(IdpConfig.GetApiResources()) .AddInMemoryApiResources(IdpConfig.GetApis()) .AddInMemoryClients(IdpConfig.GetClients()); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); }
隨意這裏改不改無所謂,由於我下面截圖,和上一篇對不上 因此在這裏說明一下post
[HttpGet] public IActionResult Get() { return new JsonResult(from c in User.Claims select new { c.Type, c.Value }); }
public async Task<IActionResult> TokenPwd() { var client = new HttpClient(); var disco = await client.GetDiscoveryDocumentAsync(_idpBaseUrl); if (disco.IsError) { return Content("獲取發現文檔失敗。error:" + disco.Error); } #region 第一種方式請求 token //var tokenclient = new TokenClient(client, new TokenClientOptions //{ // ClientId = "client pwd", // ClientSecret = "secret", // Address = disco.TokenEndpoint, //}); //var token = await tokenclient.RequestPasswordTokenAsync("alice", "alice", "api1"); #endregion var token = await client.RequestPasswordTokenAsync(new PasswordTokenRequest { Address = disco.TokenEndpoint, //下面2個屬性對應的是 IdentityServer定義的測試用戶,這裏應是 Action 參數傳遞進來的,爲了方便直接寫死的 UserName = "alice", Password = "alice", //下面3個屬性對應的是 IdentityServer定義的客戶端 ClientId = "client pwd", ClientSecret = "secret", Scope = "api1 openid profile email phone address" }); if (token.IsError) { return Content("獲取 AccessToken 失敗。error:" + token.Error); } //將token 臨時存儲到 緩存中 _memoryCache.Set("AccessToken_Pwd", token.AccessToken); return Content("獲取 AccessToken 成功。Token:" + token.AccessToken); }
public async Task<IActionResult> SuiBianPwd() { string token, apiurl = GetApiUrl("suibian"); _memoryCache.TryGetValue("AccessToken_Pwd", out token); if (string.IsNullOrEmpty(token)) { return Content("token is null"); } var client = new HttpClient(); client.SetBearerToken(token); var response = await client.GetAsync(apiurl); var result = await response.Content.ReadAsStringAsync(); if (!response.IsSuccessStatusCode) { _memoryCache.Remove("AccessToken"); return Content($"獲取 {apiurl} 失敗。StatusCode:{response.StatusCode} \r\n Token:{token} \r\n result:{result}"); } return Json(JsonConvert.DeserializeObject(result)); }
public async Task<IActionResult> IdentityInfoPwd() { string token; _memoryCache.TryGetValue("AccessToken_Pwd", out token); if (string.IsNullOrEmpty(token)) { return Content("token is null"); } var client = new HttpClient(); var disco = await client.GetDiscoveryDocumentAsync(_idpBaseUrl); if (disco.IsError) { return Content("獲取發現文檔失敗。error:" + disco.Error); } client.SetBearerToken(token); var response = await client.GetAsync(disco.UserInfoEndpoint); var result = await response.Content.ReadAsStringAsync(); if (!response.IsSuccessStatusCode) { _memoryCache.Remove("AccessToken"); return Content($"獲取 UserInfo 失敗。StatusCode:{response.StatusCode} \r\n Token:{token} \r\n result:{result}"); } return Json(JsonConvert.DeserializeObject(result)); }
訪問 http://localhost:5003/Idp/tokenpwd 獲取token成功測試
訪問 http://localhost:5003/Idp/suibianpwd 獲取api信息成功ui
訪問 http://localhost:5003/Idp/identityinfopwd 獲取成功