Идентификация ASP.NET(OWIN): как получить UserID с контроллера веб-API?

(Использование VS2013 RTW, ASP.NET MVC5)

Я видел много документации о том, как добавлять свойства в класс ApplicationUser (и таблицу) при использовании идентификатора ASP.NET. Но я не видел никакой документации о том, как иметь отдельную таблицу с контентом, который сопоставляется с таблицей ApplicationUser через внешний ключ.

Я успешно получил свой собственный файл Microsoft.AspNet.Identity.EntityFramework.IdentityDbContext, и теперь моя собственная таблица "UserPreferences" сосуществует в гармонии с различными таблицами "AspNet *" в моей базе данных SQL Server. Но я не знаю, как наилучшим образом получить текущий идентификатор пользователя, чтобы написать новую строку в таблице "UserPreferences". Обратите внимание, что проект ASP.NET MVC, но я добавил (и работаю внутри) контроллер веб-API.

У меня есть рабочее решение, которое:

            var uman = new Microsoft.AspNet.Identity.UserManager<Microsoft.AspNet.Identity.EntityFramework.IdentityUser>(new Microsoft.AspNet.Identity.EntityFramework.UserStore<Microsoft.AspNet.Identity.EntityFramework.IdentityUser>(new App1.Data.App1DbContext()));

            var uident = User.Identity;

            var userobject = uman.FindByNameAsync(uident.Name);

            var userid = userobject.Result.Id;
            // (Perform new row creation including the userid we just looked up

Считайте, что таблица AspNetUsers (как определено Framework Identity) состоит из этих полей:

-id (PK, nvarchar(128) - seems to contain a GUID, not sure why not an autoincrement integer, but I assume there are reasons for this)
-Username (nvarchar(max))
-PasswordHash (nvarchar(max))
-SecurityStamp (nvarchar(max))

Я думаю, что поле id (а не имя пользователя) является правильным полем для ссылки в этой таблице. (Я думал, что пользователь может изменить свое имя пользователя, а кто-то другой может затем принять другое имя пользователя пользователя, поэтому оба поля там вероятны.) Итак, мне нужно получить текущий идентификатор пользователя для хранения в Таблица UserPreferences, что и делает этот код. Но, похоже, неэффективно это делать.

Важным моментом является то, что в контексте System.Web.Mvc.Controller я могу сделать:

User.Identity.GetUserId()
(Runtime type of User.Identity: System.Security.Principal.GenericIdentity)

Но в контексте System.Web.Http.ApiController(Web API) я не могу, потому что этот метод не существует (тип выполнения User.Identity: System.Security.Claims.ClaimsIdentity), поэтому я должен полагайтесь на:

User.Identity.Name

и выполните дополнительный поиск, чтобы преобразовать имя в ID. Есть ли у кого-нибудь предложения по улучшению этого? Подхожу ли я к задаче записи пользовательских данных для правильного разделения таблиц?

Ответ 1

Вы должны иметь возможность получить идентификатор пользователя как на контроллере MVC, так и на веб-api-контроллере одним и тем же методом расширения в identity 1.0 RTW-пакете.

Вот расширения из пакета удостоверений:

namespace Microsoft.AspNet.Identity
{
    public static class IdentityExtensions
    {
        public static string FindFirstValue(this ClaimsIdentity identity, string claimType);
        public static string GetUserId(this IIdentity identity);
        public static string GetUserName(this IIdentity identity);
    }
}

IIdentity - это базовый интерфейс для всех типов удостоверений. Вам может потребоваться добавить "using Microsoft.AspNet.Identity", чтобы увидеть метод расширения.

BTW: относительно добавления внешней таблицы для пользователя, почему бы не использовать ApplicationUser и добавить свойство навигации в UserPreference, чтобы позволить EF обрабатывать их отношения? Это будет проще.

Ответ 2

ClaimsIdentity identity = new ClaimsIdentity(OAuthDefaults.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Name, userName));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, UserID));

ClaimTypes.NameIdentifier является требованием для функции User.Identity.GetUserId()

Ответ 3

Я использую подход с основанием претензии:

private ApplicationUser GetCurrentUser(ApplicationDbContext context)
{
  var identity = User.Identity as ClaimsIdentity;
  Claim identityClaim = identity.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier);

  return context.Users.FirstOrDefault(u => u.Id == identityClaim.Value);
}

Ответ 4

Краткое описание наилучшего ответа:

  • Install-Package Microsoft.AspNet.Identity.Core -Version 2.2.1
  • var userId = User.Identity.GetUserId();

Ответ 5

Простое решение:

var user = await UserManager.FindAsync(model.UserName, model.Password);

и свойство user.id будет содержать то, что вам нужно.