2015-09-18 10 views
7

Kontekst: Używam programu ASP.NET MVC z własnym hostem OWIN. Poniżej znajdują się pozostałe konfiguracje/ustawienia.IdentityServer3: Niektóre roszczenia nie są zwracane z serwera tożsamości

W moich Client sw serwer tożsamości (zawiadomienie AllowedScopes zestawu):

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

Oto celownicze:

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

W Identity Server, Oto konfiguracja serwera. (Zawiadomienie Klientom i zakresów są te podane powyżej):

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

Wreszcie, po stronie aplikacji Web Client, to w jaki sposób uwierzytelniania jest skonfigurowana:

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

mam zaimplementowano niestandardową klasę dla usługi 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); 
    } 
} 

Jak widzisz, roszczenia są przekazywane w tej linii:

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

Kiedy próbuję zalogować się do IdentityServer3, mogę zalogować się z powodzeniem do aplikacji internetowej klienta. JEDNAK, gdy otrzymam roszczenia użytkownika, nie widzę żadnych roszczeń tożsamości. Nie given_name, family_name, i email roszczenia. Zrzut ekranu poniżej:

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

Wszystko mógłbym przegapić? Z góry dziękuję!

+0

Konfiguracja wygląda dobrze. Głupio wiem, ale czy jesteś pewien, że uwierzytelniony użytkownik ma te roszczenia? –

+0

Hej @ScottBrady, przypuszczam, że już mają, ponieważ dodałem te roszczenia do kontekstu.AuthenticateResult (jak widać na przykładowym kodzie powyżej dla niestandardowej implementacji UsersService). – jerbersoft

Odpowiedz

5

Wreszcie znalazł rozwiązanie tego problemu.

Najpierw przeniosłem tworzenie roszczeń do przesłoniętej GetProfileDataAsync (w mojej klasie UserService). Oto mój wdrożenie go:

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

Upewnij się, że mijamy roszczeń do „context.IssueClaims” wewnątrz GetProfileDataAsync() przed zwróceniem zadanie.

A dla zainteresowanych o tym, jak moja AuthenticateLocalAsync() wygląda następująco:

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

podniosłem podobny problem na stronie projektu IdentityServer3 GitHub, który zawiera wyjaśnienie, dlaczego napotkał mój problem. Oto link: https://github.com/IdentityServer/IdentityServer3/issues/1938

+0

Co oznacza ta część kodu w metodzie "GetProfileDataAsync": var claim = context.Subject.FindFirst (item => item.Type == "sub"); if (claim! = Null) { Guid userId = new Guid (claim.Value); użytkownik = _facade.Get (userId); } – Jenan

+0

Metoda "" GetProfileDataAsync "jest wywoływana dwa razy i po pierwszym wywołaniu jest context.Subject.Identity.Name null, dlaczego jest null - czy wiesz? – Jenan

+0

@Jenan, aby odpowiedzieć na pierwsze pytanie, otrzymując" sub "(krótki dla tematu) roszczenie jest uzyskiwanie nazwy użytkownika. nevermind część _facade, ponieważ jest to mój kod do pobierania użytkownika z bazy danych Co do drugiego pytania, nie mam pojęcia, dlaczego jest on wywoływany dwa razy. Być może możesz chcieć idź do dyskusji github IdentityServer3, ktoś może być w stanie pomóc :) – jerbersoft

-1

Nie używam serwera tożsamości, ale używam Windows Identity Foundation, który, jak sądzę, wykorzystuje serwer IdentityServer. W celu uzyskania dostępu do roszczeń używać:

((ClaimsIdentity)User.Identity).Claims

+0

Witam @Rll, próbowałem tego, ale roszczenia są nadal widoczne na zrzucie ekranu w pytaniu. Dzięki i tak. :) – jerbersoft

4

Moim rozwiązaniem było dodanie listy roszczeń do mojej konfiguracji zakresu w celu zwrócenia tych roszczeń. Opisana jest dokumentacja wiki, opisana w here.

Dla klienta w pamięci wszystko, co zrobił było coś takiego:

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) 
       } 
      } 
     }; 
    } 
} 
Powiązane problemy