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出來。算什么身份認證?
答:下一節解釋。