asp.net core 使用identityServer4的密碼模式來進行身份認證(一)


IdentityServer4是ASP.NET Core的一個包含OpenID和OAuth 2.0協議的框架。具體Oauth 2.0和openId請百度。

前言本博文適用於前后端分離或者為移動產品來后端api的身份認證功能。

一 首先第一步使用Nuge包管理器下載IdentityServer4的包。

第二部,添加一個名叫Config的類。

這個類的作用是對一些api和client進行配置的。

  public static IEnumerable<IdentityResource> GetIdentityResource()
        {
            return new List<IdentityResource>
             {
                 new IdentityResources.OpenId(),
                 new IdentityResources.Profile(),
                 new IdentityResources.Email()
             };
        }
        public static IEnumerable<ApiResource> GetApiResource()
        {
            return new List<ApiResource>
            {
                new ApiResource("gateway_api","gateway service"),

                new ApiResource("user_api","user_api service"),
                //並且要把contactapi加入到apiResource,並加入到 client的allowedScopes中 
               // new ApiResource("contact_api","contact_api service")
            };
        }
        public static IEnumerable<Client> GetClients()
        {
            return new List<Client>()
          {
              new Client
              {
                    ClientId="pc",
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, //這里是指定授權的模式,選擇密碼模式,
                    ClientSecrets = { new Secret("yemobai".Sha256()) },
                     RefreshTokenUsage=TokenUsage.ReUse,
                     AlwaysIncludeUserClaimsInIdToken = true,
                     AllowOfflineAccess = true,
                    AllowedScopes=new List<string>
                    {
                        "user_api",
                    IdentityServerConstants.StandardScopes.Profile,
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.OfflineAccess
                    }

              }
          };
        }

第三步 添加start up的配置

  services.AddIdentityServer()
                 .AddDeveloperSigningCredential()
                .AddInMemoryApiResources(Config.GetApiResource())
                .AddInMemoryIdentityResources(Config.GetIdentityResource())
                .AddInMemoryClients(Config.GetClients())
                .AddResourceOwnerValidator<ResourceOwnerPasswordValidator>()
                .AddProfileService<ProfileService>()
                .AddCorsPolicyService<CorsPolicyService>() //這是IdentityServer跨域的,我嘗試開啟asp.net core 的跨域,但是identityServer不接受請求。
                ;
 public void Configure(IApplicationBuilder app, IHostingEnvironment env,ILoggerFactory loggerFactory)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();
            app.UseIdentityServer(); //啟用identityServer中間件
            app.UseCors(buider =>
            {
                buider.WithOrigins("http://localhost:8080")
                .AllowAnyHeader();
            });
            app.UseMvc();
        }

 

第四步 用戶驗證

其實identityServier4也提供了一些測試用戶來進行身份認證的實驗,這些東西都在identityServer4的官網上都有介紹。

新建一個類ResourceOwnerPasswordValidator繼承與IResourceOwnerPasswordValidator接口(IResourceOwnerPasswordValidator是Identityserver4提供的一個接口其主要工作就是驗證我們的用戶名和密碼)。

這個接口只有一個方法

   public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)

怎么獲取我們傳過來的用戶名和密碼呢?

答:在方法的參數context中,按F12進入到ResourceOwnerPasswordValidationContext這個類的定義中,具體定義的屬性如下

    //
    // 摘要:
    //     Class describing the resource owner password validation context
    public class ResourceOwnerPasswordValidationContext
    {
        public ResourceOwnerPasswordValidationContext();

        //
        // 摘要:
        //     Gets or sets the name of the user.
        public string UserName { get; set; }
        //
        // 摘要:
        //     Gets or sets the password.
        public string Password { get; set; }
        //
        // 摘要:
        //     Gets or sets the request.
        public ValidatedTokenRequest Request { get; set; }
        //
        // 摘要:
        //     Gets or sets the result.
        public GrantValidationResult Result { get; set; }
    }

可以看到 userName和passWord都已經定義好了,我們只管用就行了。

context.UserName, context.Password

就算用戶名和密碼和我的數據庫的數據對上了,該怎么返回我對用戶名和密碼的認證結果呢?

答:

如果你是一個細心的人,你會發現上面 ValidateAsync這個方法返回一個Task,可以基本上認為無返回值了。不要着急,看看ResourceOwnerPasswordValidationContext這個類的定義。

GrantValidationResult Result { get; set; }

里面有這么一個屬性。看名字都知道是驗證結果了。不出意外,我們對用戶名和密碼的驗證接口應該放在這個里面。

那下面就很簡單了。

 if (accountResult.Status=="登陸成功")
            {
                context.Result= new GrantValidationResult(accountResult.User.Id.ToString(), "admin", GetUserClaim(accountResult.User));
            }
           
            else
            {
                //驗證失敗
                context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "密碼錯誤");
            }

具體的構造函數重載,請自己看。如果有需求的不要忘了,把claim給加上。怎么 加claim呢,

最簡單的方式你數據庫驗證用戶名和密碼完后,把一些claim給帶上。

向我這樣

 public Claim[] GetUserClaim(UserInfo userInfo)
        {
            
            var claims = new Claim[] { new Claim("USERID", userInfo.UserId), new Claim("USERNAME", userInfo.UserName) };
            return claims;
        }

完整代碼

 public class ResourceOwnerPasswordValidator: IResourceOwnerPasswordValidator
    {
         private readonly IAccountService accountService;
         public ResourceOwnerPasswordValidator(IAccountService _accountService)
        {
            accountService = _accountService;
        }
        public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
        {
            var accountResult = await accountService.SignInAsync(context.UserName, context.Password);
            if (accountResult.Status=="登陸成功")
            {
                context.Result= new GrantValidationResult(accountResult.User.Id.ToString(), "admin", GetUserClaim(accountResult.User));
            }
           
            else
            {
                //驗證失敗
                context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "密碼錯誤");
            }
        }
        public Claim[] GetUserClaim(UserInfo userInfo)
        {
            
            var claims = new Claim[] { new Claim("USERID", userInfo.UserId), new Claim("USERNAME", userInfo.UserName) };
            return claims;
        }

測試結果。

是用postmen來進行測試。沒有的話請自行下載。

忘了說了,把IdentityServer4的包下載下來后 ,運行項目瀏覽器輸入http://localhost:5000/.well-known/openid-configuration  

看看identiyServer4一些接口地址。

 

然后在在postMen中輸入一下Key和value(不要把我的給抄了上去)

scope寫不寫無所謂,如果你寫的了話必須在config類中

   public static IEnumerable<ApiResource> GetApiResource()
        {
            return new List<ApiResource>
            {
                new ApiResource("gateway_api","gateway service"),

                new ApiResource("user_api","user_api service"),
                //並且要把contactapi加入到apiResource,並加入到 client的allowedScopes中 
               // new ApiResource("contact_api","contact_api service")
            };
        }

在這個方法中添加上。而且也要在

  public static IEnumerable<Client> GetClients()
        {
            return new List<Client>()
          {
              new Client
              {
                    ClientId="pc",
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
                    ClientSecrets = { new Secret("yemobai".Sha256()) },
                     RefreshTokenUsage=TokenUsage.ReUse,
                     AlwaysIncludeUserClaimsInIdToken = true,
                     AllowOfflineAccess = true,
                    AllowedScopes=new List<string>
                    {
                        "user_api",
                    IdentityServerConstants.StandardScopes.Profile,
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.OfflineAccess
                    }

              }
          };

而且也要在 AllowedScopes里面給加上。

 

結果

 

 這個時候我們就拿到了access_token和過期時間和refresh_token,

就用了IdentityServer4搞了一個access_token出來。算什么身份認證?

答:下一節解釋。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM