MVC 5 Access Claims Identity Datos de usuario

119

Estoy desarrollando una aplicación web MVC 5 utilizando el enfoque de Entity Framework 5 Database First . Estoy usando OWIN para la autenticación de usuarios. A continuación se muestra mi método de inicio de sesión dentro de mi controlador de cuenta.

public ActionResult Login(LoginViewModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        var user = _AccountService.VerifyPassword(model.UserName, model.Password, false);
        if (user != null)
        {
            var identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, model.UserName), }, DefaultAuthenticationTypes.ApplicationCookie, ClaimTypes.Name, ClaimTypes.Role);

            identity.AddClaim(new Claim(ClaimTypes.Role, "guest"));
            identity.AddClaim(new Claim(ClaimTypes.GivenName, "A Person"));
            identity.AddClaim(new Claim(ClaimTypes.Sid, user.userID)); //OK to store userID here?

            AuthenticationManager.SignIn(new AuthenticationProperties
            {
                IsPersistent = model.RememberMe
            }, identity);

            return RedirectToAction("Index", "MyDashboard");
        }
        else
        {
            ModelState.AddModelError("", "Invalid username or password.");
        }
    }
    // If we got this far, something failed, redisplay form
    return View(model);
}

Como puede ver, estoy creando un ClaimsIdentity y agregando varios reclamos, luego se lo paso a OWIN usando AuthenticationManager para realizar el inicio de sesión.

El problema que tengo es que no estoy seguro de cómo acceder a las reclamaciones en el resto de mi aplicación, ya sea en Controllers o en Razor Views.

Probé el enfoque enumerado en este tutorial

http://brockallen.com/2013/10/24/a-primer-on-owin-cookie-authentication-middleware-for-the-asp-net-developer/

Por ejemplo, probé esto en mi código de controlador en un intento de obtener acceso a los valores pasados ​​a los reclamos, sin embargo, el usuario. Reclamos es igual a nulo

var ctx = HttpContext.GetOwinContext();
ClaimsPrincipal user = ctx.Authentication.User;
IEnumerable<Claim> claims = user.Claims;

Quizás me esté perdiendo algo aquí.

ACTUALIZAR

Según la respuesta de Darin, agregué su código, pero aún no veo el acceso a las Reclamaciones. Por favor, vea la captura de pantalla a continuación que muestra lo que veo cuando coloco el cursor sobre la identidad.

ingrese la descripción de la imagen aquí

tcode
fuente
¿Puede confirmar que el navegador devuelve la cookie? ¿Quizás su configuración de seguridad exija SSL?
privilegio mínimo
@leastprivilege Gracias, lo investigaré ahora. Encontré esta pregunta en Stackoverflow, stackoverflow.com/questions/20319118/… es exactamente el mismo problema que tengo, pero desafortunadamente no hay respuesta :(
tcode
¿Cómo se inicializan sus componentes OWIN?
Derek Van Cuyk
Recientemente tuve un problema como este; Espero que esta solución ayude: stackoverflow.com/questions/34537475/…
Alexandru

Respuestas:

172

Prueba esto:

[Authorize]
public ActionResult SomeAction()
{
    var identity = (ClaimsIdentity)User.Identity;
    IEnumerable<Claim> claims = identity.Claims;
    ...
}
Darin Dimitrov
fuente
Gracias por tu ayuda. Usé su respuesta sugerida en una Acción dentro de un Controlador para intentar acceder a los valores de Reclamaciones, sin embargo, yo identifico Reclamaciones sigue siendo NULO (vea la pregunta actualizada con captura de pantalla). ¿Alguna otra idea? Aprecio tu ayuda.
tcode
No, lo siento, no tengo otras ideas. Esto siempre me ha funcionado.
Darin Dimitrov
Lo siento, una última pregunta. ¿Necesito crear mi propia clase ClaimsAuthenticationManager personalizada y Application_PostAuthenticateRequest () en Global.asax como este dotnetcodr.com/2013/02/25/… antes de que funcione mi código anterior? Gracias de nuevo.
tcode
7
Hasta que autorice por primera vez, no tendrá acceso a esto hasta después de su método de inicio de sesión, por lo que el OP no lo ve en ese momento. Debe cargar manualmente en este momento si lo desea en el método de inicio de sesión.
Adam Tuliper - MSFT
Estoy trabajando con asp.net core y buscando la manera de obtener una imagen de perfil de LinkedIn durante más de 2 horas. Estoy atascado, cansado, quiero rendirme hasta que vea tu respuesta. Quiero dar las gracias millones de veces ... +1
Vayne
36

También puedes hacer esto:

//Get the current claims principal
var identity = (ClaimsPrincipal)Thread.CurrentPrincipal;
var claims = identity.Claims;

Actualizar

Para proporcionar más explicaciones según los comentarios.

Si está creando usuarios dentro de su sistema de la siguiente manera:

UserManager<applicationuser> userManager = new UserManager<applicationuser>(new UserStore<applicationuser>(new SecurityContext()));
ClaimsIdentity identity = userManager.CreateIdentity(user, DefaultAuthenticationTypes.ApplicationCookie);

Debería tener automáticamente algunas Reclamaciones relacionadas con su identidad.

Para agregar reclamos personalizados después de que un usuario se autentica, puede hacer esto de la siguiente manera:

var user = userManager.Find(userName, password);
identity.AddClaim(new Claim(ClaimTypes.Email, user.Email));

Las afirmaciones se pueden volver a leer como Darin ha respondido anteriormente o como yo.

Los reclamos persisten cuando llama a continuación pasando la identidad en:

AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = persistCookie }, identity);
hutchonoid
fuente
Gracias, pero aún así, esto no me funciona. ¿Puedes ver mi pregunta actualizada? Además, una última pregunta. ¿Necesito crear mi propia clase ClaimsAuthenticationManager personalizada y Application_PostAuthenticateRequest () en Global.asax como este dotnetcodr.com/2013/02/25/… antes de que funcione mi código anterior? De nuevo, gracias por tu ayuda.
tcode
Hola, echaré un vistazo cuando vuelva a utilizar una PC.
hutchonoid
gracias, de verdad lo aprecio. En una etapa en la que esto está empezando a hacerme
reír
@tgriffiths Hola, he añadido una actualización para ti. Ojalá proporcione un poco más de información. Buena suerte. :)
hutchonoid
Desafortunadamente, no estoy usando el Código de Entity Framework primero integrado, por ejemplo, UserManager, etc. Pero gracias por tu entrada. Salud.
tcode
30

Hago mi propia clase extendida para ver lo que necesito, así que cuando lo necesito en mi controlador o mi Vista, solo agrego el uso a mi espacio de nombres algo como esto:

public static class UserExtended
{
    public static string GetFullName(this IPrincipal user)
    {
        var claim = ((ClaimsIdentity)user.Identity).FindFirst(ClaimTypes.Name);
        return claim == null ? null : claim.Value;
    }
    public static string GetAddress(this IPrincipal user)
    {
        var claim = ((ClaimsIdentity)user.Identity).FindFirst(ClaimTypes.StreetAddress);
        return claim == null ? null : claim.Value;
    }
    public ....
    {
      .....
    }
}

En mi controlador:

using XXX.CodeHelpers.Extended;

var claimAddress = User.GetAddress();

En mi navaja:

@using DinexWebSeller.CodeHelpers.Extended;

@User.GetFullName()
Jesús Padilla
fuente
8
return claim?.Value;porque ¿por qué no?
Halter
17

Esta es una alternativa si no desea utilizar reclamos todo el tiempo. Eche un vistazo a este tutorial de Ben Foster.

public class AppUser : ClaimsPrincipal
{
    public AppUser(ClaimsPrincipal principal)
        : base(principal)
    {
    }

    public string Name
    {
        get
        {
            return this.FindFirst(ClaimTypes.Name).Value;
        } 
    }

}

Entonces puede agregar un controlador base.

public abstract class AppController : Controller
{       
    public AppUser CurrentUser
    {
        get
        {
            return new AppUser(this.User as ClaimsPrincipal);
        }
    }
}

En tu controlador, harías:

public class HomeController : AppController
{
    public ActionResult Index()
    {
        ViewBag.Name = CurrentUser.Name;
        return View();
    }
}
Quentin
fuente
12

Para tocar más la respuesta de Darin, puede acceder a sus reclamos específicos utilizando el método FindFirst :

var identity = (ClaimsIdentity)User.Identity;
var role = identity.FindFirst(ClaimTypes.Role).Value;
Eric Bridges
fuente
O este también string myValue = identity.FindFirstValue ("MyClaimType");
Juan Carlos Puerto
¿Qué sucede si FindFirst no encuentra ninguna reclamación con el tipo "rol"? excepción nula?
Phil
10

También puedes hacer esto.

IEnumerable<Claim> claims = ClaimsPrincipal.Current.Claims;
angularsen
fuente
8

Recuerde que para consultar el IEnumerable debe hacer referencia a system.linq.
Le dará el objeto de extensión necesario para hacer:

CaimsList.FirstOrDefault(x=>x.Type =="variableName").toString();
Marc Sedote Sossou
fuente
7

La versión más corta y simplificada de @Rosdi Kasim'd answer es

string claimvalue = ((System.Security.Claims.ClaimsIdentity)User.Identity).
    FindFirst("claimname").Value;

Claimname es el reclamo que desea recuperar, es decir, si está buscando el reclamo "StreedAddress", la respuesta anterior será así

string claimvalue = ((System.Security.Claims.ClaimsIdentity)User.Identity).
    FindFirst("StreedAddress").Value;
noman zafar
fuente
proporcionar el ejemplo "valor de reclamo" me ahorró tiempo. Gracias
Nour Lababidi
6
Request.GetOwinContext().Authentication.User.Claims

Sin embargo, es mejor agregar las reclamaciones dentro del método "GenerateUserIdentityAsync", especialmente si regenerateIdentity en Startup.Auth.cs está habilitado.

Albahaca banbouk
fuente
El GenerateUserIdentityAsyncfue una sugerencia impresionante, he pasado por alto totalmente. Muchas gracias Basil.
timmi4sa
2

Según la clase ControllerBase, puede obtener las notificaciones del usuario que ejecuta la acción.

ingrese la descripción de la imagen aquí

así es como puede hacerlo en 1 línea.

var claims = User.Claims.ToList();
conterio
fuente
1
var claim = User.Claims.FirstOrDefault(c => c.Type == "claim type here");
Felipe Deveza
fuente
0

Lo usé así en mi controlador base. Solo compartiendo para estar listo para usar.

    public string GetCurrentUserEmail() {
        var identity = (ClaimsIdentity)User.Identity;
        IEnumerable<Claim> claims = identity.Claims;
        var email = claims.Where(c => c.Type == ClaimTypes.Email).ToList();
        return email[0].Value.ToString();
    }

    public string GetCurrentUserRole()
    {
        var identity = (ClaimsIdentity)User.Identity;
        IEnumerable<Claim> claims = identity.Claims;
        var role = claims.Where(c => c.Type == ClaimTypes.Role).ToList();
        return role[0].Value.ToString();
    }
BM
fuente