Asp.net

IdentityServer3:一些聲明沒有從身份伺服器返回

  • May 12, 2016

上下文: 我正在使用帶有 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_namefamily_nameemail聲明。截圖如下:

如您所見,不包括 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)
               }
           }
        };
   }
}

引用自:https://stackoverflow.com/questions/32654322