Identidad ASP.NET (OWIN): ¿Cómo obtener ID de usuario desde un controlador API web?

(Usando VS2013 RTW, ASP.NET MVC5)

He visto mucha documentación sobre cómo agregar propiedades a la clase ApplicationUser (y a la tabla) cuando utilizo la identidad de ASP.NET. Pero no he visto ninguna documentación sobre cómo tener una tabla separada con contenido que se asigna a la tabla ApplicationUser a través de una clave externa.

He obtenido mi propio Microsoft.AspNet.Identity.EntityFramework.IdentityDbContext, y ahora mi propia tabla “UserPreferences” coexiste en armonía con las diversas tablas “AspNet *” en mi base de datos de SQL Server. Pero no tengo claro cuál es la mejor manera de obtener la identificación del usuario actual para escribir una nueva fila en la tabla “Preferencias del usuario”. Tenga en cuenta que el proyecto es ASP.NET MVC, pero he agregado (y estoy trabajando dentro de) un controlador de API web.

Tengo una solución de trabajo, que es:

var uman = new Microsoft.AspNet.Identity.UserManager(new Microsoft.AspNet.Identity.EntityFramework.UserStore(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 

Tenga en cuenta que la tabla AspNetUsers (tal como se define en el marco Identity) consta de estos campos:

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

Creo que el campo id (no el nombre de usuario) es el campo correcto para referenciar en esta tabla. (Estaba pensando que un usuario puede cambiar su nombre de usuario, y que otra persona podría asumir el nombre de usuario del otro usuario, por lo que es probable que existan ambos campos). Entonces, necesito obtener el ID del usuario actual para el almacenamiento en el Tabla “Preferencias de usuario”, que es lo que hace el código anterior. Pero parece ineficiente tener que hacer esta búsqueda.

Un punto importante es que en el contexto de System.Web.Mvc.Controller, puedo hacer lo siguiente:

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

Pero en el contexto de System.Web.Http.ApiController (API web), no puedo porque ese método no existe (tipo de tiempo de ejecución de User.Identity: System.Security.Claims.ClaimsIdentity) por lo que debo confiar en :

 User.Identity.Name 

y haz la búsqueda extra para convertir Nombre a ID. ¿Alguien tiene alguna sugerencia de cómo se puede mejorar esto? ¿Me estoy acercando a la tarea de escribir datos de usuario en tablas separadas de la manera correcta?

Debería poder obtener la identificación de usuario tanto en el controlador MVC como en el controlador de API web mediante el mismo método de extensión en el paquete identidad 1.0 RTW .

Aquí están las extensiones del paquete de identidad:

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

El IIdentity es la interfaz base para todos los tipos de identidad. Es posible que deba agregar “using Microsoft.AspNet.Identity” para ver el método de extensión.

Por cierto: con respecto a agregar una tabla foránea para el usuario, ¿por qué no usar ApplicationUser y agregar propiedad de navegación a UserPreference para que EF pueda manejar su relación? Eso será más fácil.

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

ClaimTypes.NameIdentifier es el reclamo de la función User.Identity.GetUserId()

Estoy usando un enfoque basado en reclamos:

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

Breve descripción de la mejor respuesta:

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