IdentityServer4與API單項目整合(net core 3.X)
- 2020 年 9 月 21 日
- 筆記
- IdentityServer4
一、創建一個空的api項目
添加identityserver4的nuget包
配置config文件
public static IEnumerable<IdentityResource> GetIdentityResources() { return new IdentityResource[] { new IdentityResources.OpenId(), new IdentityResources.Profile(), }; } /// <summary> /// API資訊 /// </summary> /// <returns></returns> public static IEnumerable<ApiResource> GetApis() { return new[] { new ApiResource(IdentityServerConstants.LocalApi.ScopeName), new ApiResource("manageApi", "Demo API with Swagger") }; } /// <summary> /// 客服端資訊 /// </summary> /// <returns></returns> public static IEnumerable<Client> GetClients() { return new[] { new Client { ClientId = "clientId",//客服端名稱 ClientName = "Swagger UI for demo_api",//描述 AllowedGrantTypes = GrantTypes.ResourceOwnerPassword ,//指定允許的授權類型(AuthorizationCode,Implicit,Hybrid,ResourceOwner,ClientCredentials的合法組合)。 AllowAccessTokensViaBrowser = true,//是否通過瀏覽器為此客戶端傳輸訪問令牌 AccessTokenLifetime = 3600*24, AuthorizationCodeLifetime=3600*24, ClientSecrets ={new Secret("secret".Sha256())}, //RedirectUris = //{ // "//localhost:59152/oauth2-redirect.html" //}, AllowedCorsOrigins = new string[]{ "//localhost:9012", "//101.133.234.110:21004", "//115.159.83.179:21004" }, AllowedScopes = { "manageApi", IdentityServerConstants.LocalApi.ScopeName }//指定客戶端請求的api作用域。 如果為空,則客戶端無法訪問 } }; }
在Startup.cs中注入IdentityServer服務並使用中間件
//配置身份伺服器與記憶體中的存儲,密鑰,客戶端和資源 services.AddIdentityServer() .AddDeveloperSigningCredential() .AddInMemoryApiResources(config.GetApis())//添加api資源 .AddInMemoryClients(config.GetClients())//添加客戶端 .AddInMemoryIdentityResources(config.GetIdentityResources())//添加對OpenID Connect的支援 //使用自定義驗證 .AddResourceOwnerValidator<CustomResourceOwnerPasswordValidator>() .AddProfileService<ProfileService>();
//啟用IdentityServer app.UseIdentityServer();
接下來,我們去實現CustomResourceOwnerPasswordValidator這個類
創建一個CustomResourceOwnerPasswordValidator類,繼承IResourceOwnerPasswordValidator
public class CustomResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator { public Task ValidateAsync(ResourceOwnerPasswordValidationContext context) { throw new NotImplementedException(); } }
接下來,我們就是些驗證了
我們創建一個服務,去獲取資料庫裡面的用戶,驗證是否有當前登錄的用戶
這裡我們創建了一個userservice來驗證我們的輸入用戶是否存在
public class UserService : IUserService { public async Task<TestPhoneUser> ValidateCredentials(string nameorphone, string password) { var dto= TestUser.FirstOrDefault(c => c.Phone == nameorphone && password == c.PassWord); if (dto != null) return dto; else return null; } public class TestPhoneUser { /// <summary> /// 唯一標識 /// </summary> public int Id { get; set; } /// <summary> /// 手機號 /// </summary> public string Phone { get; set; } /// <summary> /// 密碼 /// </summary> public string PassWord { get; set; } } public List<TestPhoneUser> TestUser = new List<TestPhoneUser> { new TestPhoneUser { Id=1, Phone="12345678911", PassWord="123qwe" },new TestPhoneUser { Id=2, Phone="123", PassWord="123qwe" } }; }
現在,我們去完善CustomResourceOwnerPasswordValidator
public class CustomResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator { private readonly IUserService _userService; public CustomResourceOwnerPasswordValidator(IUserService userService) { _userService = userService; } public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context) { var dto = await _userService.ValidateCredentials(context.UserName, context.Password); if (dto!=null) { context.Result = new GrantValidationResult( dto.Id.ToString(), "pwd", DateTime.Now); } else { //驗證失敗 context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "用戶名密碼錯誤"); } } }
再要配置profile
public class ProfileService:IProfileService { public Task GetProfileDataAsync(ProfileDataRequestContext context) { context.IssuedClaims = context.Subject.Claims.ToList(); return Task.CompletedTask; } public Task IsActiveAsync(IsActiveContext context) { context.IsActive = true; return Task.CompletedTask; } }
注入剛剛添加的服務
services.AddScoped<IUserService, UserService>();
services.AddScoped<IProfileService, ProfileService>();
在Startup.cs中加入identityServer驗證
//用戶校驗 services.AddLocalApiAuthentication(); services.AddAuthorization(options => { options.AddPolicy(IdentityServerConstants.LocalApi.PolicyName, policy => { policy.AddAuthenticationSchemes(IdentityServerConstants.LocalApi.AuthenticationScheme); policy.RequireAuthenticatedUser(); }); });
app.UseAuthentication();
postman測試
反覆驗證了很多遍,都沒有問題(因為我之前core2.x的時候就是這樣寫的)
最後去identityserver官網,找到了問題所在
現在的資源都換成了apiscope
然後,我把ApiResource都換成了ApiScope然後再運行
ok,完美!!!(這個坑,坑了我一下午)
最後再給api添加驗證就行了
[Authorize(LocalApi.PolicyName)]
訪問api
訪問成功