2015-09-18 9 views
7

Kontext: Ich verwende ASP.NET MVC mit OWIN-Self-Host. Im Folgenden finden Sie den Rest der Konfigurationen/Setup.IdentityServer3: Einige Ansprüche werden nicht vom Identitätsserver zurückgegeben

In meinem -Client s in Identitätsserver (man beachte die AllowedScopes set):

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 
       } 
      } 
     }; 
    } 
} 

Hier sind die Scopes:

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(); 
    } 
} 

Im Identity Server, Hier ist, wie der Server konfiguriert ist. (Beachten Sie den Clients und Scopes sind die, die oben angegeben):

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); 

schließlich auf der Client-Web-Anwendung Seite, das ist, wie Auth eingerichtet ist:

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" 
     }); 

Ich habe eine benutzerdefinierte Klasse für IUserService implementiert:

Wie Sie sehen, sind die Ansprüche in dieser Zeile übergeben:

context.AuthenticateResult = new AuthenticateResult(user.Id.ToString(), user.EmailAddress, claims); 

Als ich in zu IdentityServer3 versuchen anmelden, kann ich erfolgreich an die Client-Web-Anwendung anmelden. JEDOCH, wenn ich die Benutzeransprüche bekomme, sehe ich keine Identitätsansprüche. No Vorname, Familienname und E-Mail Ansprüche. Screenshot unten:

As you can see, there are no given_name, family_name and email claims included.

Alles, was ich vielleicht verpasst haben? Danke im Voraus!

+0

Ihre Konfiguration sieht gut aus. Dumm ich weiß, aber sind Sie sicher, dass der authentifizierte Benutzer diese Ansprüche hat? –

+0

Hey @ScottBrady, ich nehme an, sie haben bereits, weil ich diese Ansprüche auf den Kontext hinzugefügt habe.AuthenticateResult (wie Sie im obigen Beispielcode für die benutzerdefinierte UsersService-Implementierung sehen). – jerbersoft

Antwort

5

fand schließlich die Lösung für dieses Problem.

Zuerst habe ich die Erstellung von Ansprüchen auf das überschriebene GetProfileDataAsync (in meiner UserService-Klasse) verschoben. Hier ist meine Implementierung davon:

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); 
     } 

Stellen Sie sicher, dass wir die Ansprüche auf die „context.IssueClaims“ innerhalb des GetProfileDataAsync() vor der Rückkehr in die Aufgabe übergeben.

Und für diejenigen interessiert, wie meine AuthenticateLocalAsync() wie folgt aussieht:

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); 

hob ich ein ähnliches Problem in IdentityServer3 GitHub Projektseite, die die Erklärung enthält, warum ich mein Problem aufgetreten. Hier ist der Link: https://github.com/IdentityServer/IdentityServer3/issues/1938

+0

Was bedeutet dieser Teil des Codes in der Methode "GetProfileDataAsync": var claim = context.Subject.FindFirst (item => item.Type == "sub"); if (claim! = Null) { Guid userId = neue Guid (claim.Value); Benutzer = _facade.Get (userId); } – Jenan

+0

Die Methode "" GetProfileDataAsync "wird zweimal aufgerufen und nach dem ersten Aufruf ist context.Subject.Identity.Name null, warum ist null - wissen Sie? – Jenan

+0

@Jenan, um Ihre erste Frage zu beantworten, bekommen die" sub "(kurz für Thema) Behauptung erhält den Benutzernamen. vergiss den _facade Teil, da das mein Code ist, um den Benutzer von der Datenbank zu erhalten. Was deine zweite Frage betrifft, habe ich keine Idee, warum sie zweimal genannt wird. Vielleicht möchtest du vielleicht Gehen Sie zur IdentityServer3 Github-Diskussion, jemand könnte vielleicht helfen. :) – jerbersoft

-1

Ich verwende nicht den Identity Server, aber ich benutze die Windows Identity Foundation, die ich glaube was IdentityServer verwendet. Um die Ansprüche für den Zugriff auf die ich benutze:

((ClaimsIdentity)User.Identity).Claims

+0

Hallo @rll, ich habe das ausprobiert aber die Ansprüche sind immer noch was man auf dem Screenshot in der Frage sehen kann. Danke trotzdem. :) – jerbersoft

4

Meine Lösung bestand darin, eine Liste von Ansprüchen zu meiner Scope-Konfiguration hinzuzufügen, um diese Ansprüche zurückzugeben. Die Dokumentation des Wikis here beschrieb es.

Für eine In-Memory-Client alles, was ich war so etwas tat:

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) 
       } 
      } 
     }; 
    } 
}