Asp.net
IdentityServer3:一些聲明沒有從身份伺服器返回
上下文: 我正在使用帶有 OWIN 自主機的 ASP.NET MVC。以下是其餘的配置/設置。
在身份伺服器中的我的Client中(注意****AllowedScopes集):
public static class InMemoryClientSource { public static List<Client> GetClientList() { return new List<Client>() { new Client() { ClientName = "Admin website", ClientId = "admin", Enabled = true, Flow = Flows.Hybrid, ClientSecrets = new List<Secret>() { new Secret("admin".Sha256()) }, RedirectUris = new List<string>() { "https://admin.localhost.com/" }, PostLogoutRedirectUris = new List<string>() { "https://admin.localhost.com/" }, AllowedScopes = new List<string> { Constants.StandardScopes.OpenId, Constants.StandardScopes.Profile, Constants.StandardScopes.Email, Constants.StandardScopes.Roles } } }; } }這是范圍:
public static class InMemoryScopeSource { public static List<Scope> GetScopeList() { var scopes = new List<Scope>(); scopes.Add(StandardScopes.OpenId); scopes.Add(StandardScopes.Profile); scopes.Add(StandardScopes.Email); scopes.Add(StandardScopes.Roles); return scopes.ToList(); } }在Identity Server中,這是伺服器的配置方式。(注意客戶端和範圍是上面提供的):
var userService = new UsersService( .... repository passed here .... ); var factory = new IdentityServerServiceFactory() .UseInMemoryClients(InMemoryClientSource.GetClientList()) .UseInMemoryScopes(InMemoryScopeSource.GetScopeList()); factory.UserService = new Registration<IUserService>(resolver => userService); var options = new IdentityServerOptions() { Factory = factory, SigningCertificate = Certificates.Load(), // certificates blah blah SiteName = "Identity" }; app.UseIdentityServer(options);最後,在客戶端 Web 應用程序端,這是設置身份驗證的方式:
app.UseCookieAuthentication(new CookieAuthenticationOptions() { AuthenticationType = "Cookies" }); app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions() { Authority = "https://id.localhost.com", ClientId = "admin", RedirectUri = "https://admin.localhost.com/", PostLogoutRedirectUri = "https://admin.localhost.com/", ResponseType = "code id_token token", Scope = "openid profile email roles", ClientSecret = "admin", SignInAsAuthenticationType = "Cookies" });我為 IUserService 實現了一個自定義類:
public class UsersService : UserServiceBase { public UsersService( .... repository passed here .... ) { //.... ctor stuff } public override Task AuthenticateLocalAsync(LocalAuthenticationContext context) { // var user = .... retrieved from database ..... // ... auth logic ... if (isAuthenticated) { var claims = new List<Claim>(); claims.Add(new Claim(Constants.ClaimTypes.GivenName, user.FirstName)); claims.Add(new Claim(Constants.ClaimTypes.FamilyName, user.LastName)); claims.Add(new Claim(Constants.ClaimTypes.Email, user.EmailAddress)); context.AuthenticateResult = new AuthenticateResult(user.Id.ToString(), user.EmailAddress, claims); } return Task.FromResult(0); } }如您所見,聲明在這一行中傳遞:
context.AuthenticateResult = new AuthenticateResult(user.Id.ToString(), user.EmailAddress, claims);當我嘗試登錄 IdentityServer3 時,我可以成功登錄到客戶端 Web 應用程序。但是,當我收到使用者聲明時,我看不到任何身份聲明。沒有given_name、family_name和email聲明。截圖如下:
有什麼我可能錯過的嗎?提前致謝!
終於找到了解決這個問題的辦法。
首先,我將聲明的創建移至被覆蓋的 GetProfileDataAsync(在我的 UserService 類中)。這是我的實現:
public override Task GetProfileDataAsync(ProfileDataRequestContext context) { var identity = new ClaimsIdentity(); UserInfo user = null; if (!string.IsNullOrEmpty(context.Subject.Identity.Name)) user = _facade.Get(context.Subject.Identity.Name); else { // get the sub claim var claim = context.Subject.FindFirst(item => item.Type == "sub"); if (claim != null) { Guid userId = new Guid(claim.Value); user = _facade.Get(userId); } } if (user != null) { identity.AddClaims(new[] { new Claim(Constants.ClaimTypes.PreferredUserName, user.Username), new Claim(Constants.ClaimTypes.Email, user.EmailAddress) // .. other claims }); } context.IssuedClaims = identity.Claims; //<- MAKE SURE you add the claims here return Task.FromResult(identity.Claims); }在返回任務之前,請確保我們將聲明傳遞給 GetProfileDataAsync() 中的“context.IssueClaims”。
對於那些對我的 AuthenticateLocalAsync() 外觀感興趣的人:
var user = _facade.Get(context.UserName); if (user == null) return Task.FromResult(0); var isPasswordCorrect = BCrypt.Net.BCrypt.Verify(context.Password, user.Password); if (isPasswordCorrect) { context.AuthenticateResult = new AuthenticateResult(user.Id.ToString(), user.Username); } return Task.FromResult(0);我在 IdentityServer3 GitHub 項目頁面中提出了一個類似的問題,其中包含對我遇到問題的原因的解釋。這是連結: https ://github.com/IdentityServer/IdentityServer3/issues/1938
我的解決方案是將聲明列表添加到我的範圍配置中,以便返回這些聲明。此處的 wiki 文件對其進行了描述。
對於記憶體中的客戶端,我所做的一切都是這樣的:
public class Scopes { public static IEnumerable<Scope> Get() { return new Scope[] { StandardScopes.OpenId, StandardScopes.Profile, StandardScopes.Email, StandardScopes.Roles, StandardScopes.OfflineAccess, new Scope { Name = "yourScopeNameHere", DisplayName = "A Nice Display Name", Type = ScopeType.Identity, Emphasize = false, Claims = new List<ScopeClaim> { new ScopeClaim("yourClaimNameHere", true), new ScopeClaim("anotherClaimNameHere", true) } } }; } }
