Как идентификатор пользователя соотносится между локальным хранилищем пользователей и провайдерами oauth?
Мой контекст
Я пытаюсь создать собственное хранилище пользователя / роли для удостоверения ASP.NET.
Фон
Здесь, в SO, есть несколько вопросов о получении идентификатора пользователя при использовании ASP.NET Identity. Большинство из них решают разбор NameIdentifier
Запрос.
Тем не менее, большинство из них, кажется, пропускают точку импорта. При использовании OAuth NameIdentifier
кажется, указывают на идентичность, которую возвратил поставщик OAuth.
Это можно наблюдать, установив точку останова в AccountController сразу после завершения аутентификации.
Моя проблема
Если вы посмотрите на UserStore, вы можете увидеть, что GetUserIdAsync
вернет Id
из IdentityUser
объект, который является вашим внутренним идентификатором из базы данных. Пока все хорошо.
Однако, если вы посмотрите на UserManager, он получил следующий код:
/// <summary>
/// Returns the User ID claim value if present otherwise returns null.
/// </summary>
/// <param name="principal">The <see cref="T:System.Security.Claims.ClaimsPrincipal" /> instance.</param>
/// <returns>The User ID claim value, or null if the claim is not present.</returns>
/// <remarks>The User ID claim is identified by <see cref="F:System.Security.Claims.ClaimTypes.NameIdentifier" />.</remarks>
public virtual string GetUserId(ClaimsPrincipal principal)
{
if (principal == null)
throw new ArgumentNullException("principal");
return principal.FindFirstValue(this.Options.ClaimsIdentity.UserIdClaimType);
}
.. который выглядит просто отлично на первом пике. Но если вы посмотрите на постоянное значение для UserIdClaimType
это так же, как ClaimTypes.NameIdentifier
, Таким образом он получит идентификатор пользователя oauth.
Код, который не работает из-за вышеуказанной проблемы:
//this returns the oauth id, can't be used to work with the application user
var id = await _userManager.GetUserIdAsync(currentClaimPrincipal);
//this returns null as it internally uses the above line
await user = _userManager.GetUserAsync(currentClaimPrincipal);
Код выше будет вызывать UserStore.FindByIdAsync
с идентификатором пользователя присяги в качестве идентификатора пользователя. поэтому пользовательское хранилище будет пытаться найти пользователя приложения, используя неправильный ключ.
Хаком было бы использовать oAuth userId в качестве PK в локальной таблице пользователей, но это может привести к поломке, если два oauth-провайдера вернут один и тот же идентификатор (что не исключено). Это также не будет работать, когда несколько идентификаторов oauth связаны с одним и тем же пользователем приложения.
Мой вопрос
Я делаю что-то неправильно? Как идентификаторы пользователей связаны между хранилищем пользователей приложения и oauth-провайдерами?
1 ответ
Вы не должны вызывать GetUserId с принципалом утверждений от поставщика OAuth. Единственный ClaimsPrincipal, который должен использоваться с этим, является одним, сгенерированным через ClaimsPrincipalUserFactory, который использует идентичность. Связывание OAuth с локальным пользователем обычно выполняется с помощью метода AddLogin, который связывает идентификатор OAuth с идентификатором локального пользователя.