2015-09-18 4 views
7

Контекст: Я использую ASP.NET MVC с собственным хостом OWIN. Ниже приведены остальные настройки/настройки.IdentityServer3: Некоторые претензии не возвращаются с сервера идентификации

В моих клиента с в сервере личных данных (обратите внимание на 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(); 
    } 
} 

В Сервер идентификации, вот как настроен сервер. (Обратите внимание на клиентов и SCOPES являются те, приведенных выше):

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

Наконец, на стороне клиента веб-приложений, это как авторизация устанавливается:

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, я могу успешно выполнить вход в клиентское веб-приложение. HOWEVER, когда я получаю претензии пользователей, я не вижу никаких претензий в отношении личности. № имя_источника, фамилия и электронная почта претензии. Снимок экрана ниже:

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

Все, что я мог пропустить? Заранее спасибо!

+0

Ваша конфигурация выглядит отлично. Глупый я знаю, но вы уверены, что у аутентифицированного пользователя есть эти претензии? –

+0

Эй, @ScottBrady, я предполагаю, что они уже есть, потому что я добавил эти утверждения в контекст. AtthenticateResult (как вы видите на примере кода выше для пользовательской реализации UserService). – jerbersoft

ответ

5

Наконец нашел решение этой проблемы.

Во-первых, я переместил создание претензий к переопределенному 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); 
     } 

Убедитесь, что мы передаем претензии к «context.IssueClaims» внутри GetProfileDataAsync(), прежде чем вернуться задачу.

А для тех, кто заинтересован в том, как мой 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

+0

Что означает эта часть кода в методе «GetProfileDataAsync»: var Claim = context.Subject.FindFirst (item => item.Type == "sub"); если (претензии! = Null) { Guid userId = новый Guid (претензия.значение); user = _facade.Get (userId); } – Jenan

+0

Метод «GetProfileDataAsync» вызывается дважды и после первого вызова является context.Subject.Identity.Name null, why is null - знаете ли вы? – Jenan

+0

@Jenan, чтобы ответить на ваш первый вопрос, получив «sub» (короткое для предмета) претензия получает имя пользователя. nevermind часть _facade, так как это мой код для получения пользователя из базы данных. Что касается вашего второго вопроса, я понятия не имею, почему он вызывается дважды. Возможно, вы захотите перейдите на обсуждение IdentityServer3 github, кто-то может помочь. :) – jerbersoft

-1

Я не использую сервер идентификации, однако я использую Windows Identity Foundation, который, я считаю, использует IdentityServer. Для того, чтобы получить доступ к претензии, которые я использую:

((ClaimsIdentity)User.Identity).Claims

+0

Привет @rll, я пробовал это, но претензии все еще есть то, что вы можете видеть на скриншоте в вопросе. Спасибо, в любом случае. :) – jerbersoft

4

Мое решение состояло в том, чтобы добавить список претензий к моей конфигурации области, чтобы вернуть эти претензии. Документация wiki here описала это.

Для клиента в памяти все, что я сделал что-то вроде этого:

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