IdentityServer4 (2) 密碼受權(Resource Owner Password)

寫在前面

一、源碼(.Net Core 2.2)

  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),這裏多了一個概念就是【用戶】,帳號密碼須要用戶提供給客戶端緩存

1、IdentityServer修改

一、添加一個新的客戶端,IdpConfig.GetClients()

       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);
        }

2、API修改

一、修改 SuiBianController Get() 返回內容 

  隨意這裏改不改無所謂,由於我下面截圖,和上一篇對不上 因此在這裏說明一下post

   [HttpGet]
   public IActionResult Get()
   {
       return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
   }

3、客戶端修改

一、添加一個 Action 請求 AccessToken

   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);
   }

二、添加一個Action 測試請求 api1

 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));
        }

三、添加一個Action 測試獲取用戶認證信息

    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));
    } 

3、客戶端測試

一、獲取 token

  訪問 http://localhost:5003/Idp/tokenpwd 獲取token成功測試

二、請求 api1

  訪問 http://localhost:5003/Idp/suibianpwd 獲取api信息成功ui

  

三、獲取用戶認證信息

  訪問 http://localhost:5003/Idp/identityinfopwd 獲取成功

  

相關文章
相關標籤/搜索