Saltar al contenido

¿Cómo obtengo un usuario actual en .NET Core Web API (de JWT Token)?

Nuestro team de redactores ha estado mucho tiempo buscando la solución a tu pregunta, te regalamos la respuestas así que esperamos resultarte de gran apoyo.

Solución:

La respuesta aceptada no funcionó para mí. No estoy seguro de si eso se debe a que uso .NET Core 2.0 o a otra cosa, pero parece que el marco asigna el reclamo de asunto a un reclamo de NameIdentifier. Entonces, lo siguiente funcionó para mí:

string userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;

Tenga en cuenta que esto asume el Sujeto sub El reclamo se establece en el JWT y su valor es la identificación del usuario.

De forma predeterminada, el controlador de autenticación JWT en .NET asignará la notificación secundaria de un token de acceso JWT al System.Security.Claims.ClaimTypes.NameIdentifier tipo de reclamo. [Source]

También hay un hilo de discusión en GitHub donde concluyen que este comportamiento es confuso.

Puedes usar este método:

var email = User.FindFirst("sub")?.Value;

En mi caso estoy usando el correo electrónico como un valor único

Parece que mucha gente está mirando esta pregunta, así que me gustaría compartir más información que aprendí desde que hice la pregunta hace un tiempo. Aclara algunas cosas (al menos para mí) y no era tan obvio (para mí como novato de .NET).

Como Marcus Höglund mencionado en los comentarios:

Debería ser lo mismo para “api web”. En ASP.NET Core Mvc y Web Api se fusionan para usar el mismo controlador.

Eso es definitivamente true y absolutamente correcto.


Porque todo es igual en .NET y .NET Core.

Antes era nuevo en .NET Core y, de hecho, en el mundo completo de .NET. La información importante que faltaba era que en .NET y .NET Core toda la autenticación se puede reducir al espacio de nombres System.Security.Claims con su ClaimsIdentity, ClaimsPrinciple y Claims.Properties. Y, por lo tanto, se usa en ambos tipos de controlador .NET Core (API y MVC o Razor o …) y es accesible a través de HttpContext.User.

Una nota al margen importante que todos los tutoriales se perdieron para contar.

Entonces, si comienza a hacer algo con tokens JWT en .NET, no olvide confiar también en ClaimsIdentity, ClaimsPrinciple y Claim.Properties. Se trata de eso. Ahora lo sabes. Fue señalado por Heringer en uno de los comentarios.


TODOS los middlewares de autenticación basados ​​en reclamos (si se implementan correctamente) completarán el HttpContext.User con las reclamaciones recibidas durante la autenticación.

Por lo que entiendo ahora, esto significa que uno puede confiar con seguridad en los valores en el HttpContext.User. Pero espera un poco para saber qué tener en cuenta al seleccionar el middleware. Ya hay muchos middleware de autenticación diferentes disponibles (además de .UseJwtAuthentication()).

Con pequeños métodos de extensión personalizados, ahora puede obtener la identificación de usuario actual (más precisa la afirmación del asunto) así

 public static string SubjectId(this ClaimsPrincipal user)  return user?.Claims?.FirstOrDefault(c => c.Type.Equals("sub", StringComparison.OrdinalIgnoreCase))?.Value; 

O usas la versión en la respuesta de Ateik.


PERO ESPERA: hay una cosa extraña

Lo siguiente que me confundió fue: de acuerdo con la especificación de OpenID Connect, estaba buscando el reclamo “sub” (el usuario actual) pero no pude encontrarlo. Me gusta Honza Kalfus no pudo hacer en su respuesta.

¿Por qué?

Porque Microsoft es “a veces” “un poco” diferente. O al menos hacen un poco más (e inesperadas) las cosas. Por ejemplo, el middleware oficial de autenticación de Microsoft JWT Bearer mencionado en la pregunta original. Microsoft decidió convertir notificaciones (los nombres de las notificaciones) en todo su middleware de autenticación oficial (por razones de compatibilidad, no sé con más detalle).

No encontrará un reclamo “sub” (aunque es el único reclamo especificado por OpenID Connect). Porque se convirtió a estos elegantes ClaimTypes. No todo es malo, le permite agregar asignaciones si necesita asignar diferentes reclamos en un nombre interno único.

O se queda con la denominación de Microsoft (y tiene que tenerlo en cuenta cuando agrega o usa un middleware que no es de Microsoft) o descubre cómo activar la asignación de notificaciones para el middleware de Microsoft.

En el caso de JwtBearerAuthentication, está hecho (hágalo temprano en StartUp o al menos antes de agregar el middleware):

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

Si desea seguir con los nombres de Microsoft, el reclamo del sujeto (no me gane, no estoy seguro en este momento si Nombre es el mapeo correcto):

    public static string SubjectId(this ClaimsPrincipal user)  return user?.Claims?.FirstOrDefault(c => c.Type.Equals(ClaimTypes.NameIdentifier, StringComparison.OrdinalIgnoreCase))?.Value; 

Tenga en cuenta que las otras respuestas usan el método FindFirst más avanzado y mucho más conveniente. Aunque mis ejemplos de código lo muestran sin aquellos, es posible que deba ir con ellos.

Por lo tanto, todos sus reclamos se almacenan y son accesibles (a través de un nombre u otro) en el HttpContext.User.


Pero, ¿dónde está mi ficha?

No sé para el otro middleware, pero la autenticación de portador JWT permite guardar el token para cada solicitud. Pero esto necesita ser activado (en StartUp.ConfigureServices(...).

services
  .AddAuthentication("Bearer")
  .AddJwtBearer("Bearer", options => options.SaveToken = true);

El token real (en toda su forma críptica) como string (o null) se puede acceder a través de

HttpContext.GetTokenAsync("Bearer", "access_token")

Ha habido una versión anterior de este método (esto funciona para mí en .NET Core 2.2 sin advertencia obsoleta).

Si necesita analizar y extraer valores de este string puede que la pregunta Cómo decodificar el token JWT ayude.


Bueno, espero que ese resumen también te ayude.

Acuérdate de que tienes la capacidad de agregar una reseña .

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *