MVC 5 Access Claims Identity Données utilisateur

119

Je développe une application Web MVC 5 en utilisant l' approche Entity Framework 5 Database First . J'utilise OWIN pour l'authentification des utilisateurs. Ci-dessous, ma méthode de connexion dans mon contrôleur de compte.

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

Comme vous pouvez le voir, je crée un ClaimsIdentity et y ajoute plusieurs revendications, puis je le transmets à OWIN à l'aide de AuthenticationManager pour effectuer la connexion.

Le problème que je rencontre est que je ne sais pas comment accéder aux revendications dans le reste de mon application, que ce soit dans les contrôleurs ou dans les vues Razor.

J'avais essayé l'approche listée dans ce tutoriel

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

Par exemple, j'ai essayé ceci dans mon code de contrôleur pour tenter d'accéder aux valeurs passées dans les revendications, cependant, l'utilisateur.Claims est égal à null

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

Il me manque peut-être quelque chose ici.

METTRE À JOUR

Sur la base de la réponse de Darin, j'ai ajouté son code mais je n'arrive toujours pas à voir l'accès aux revendications. Veuillez voir la capture d'écran ci-dessous montrant ce que je vois lorsque je passe la souris sur l'identité.

entrez la description de l'image ici

tcode
la source
Pouvez-vous confirmer que le cookie est renvoyé par le navigateur? Peut-être que vos paramètres de sécurité exigent SSL?
leastprivilege
@leastprivilege Merci, je vais examiner cela maintenant. J'ai trouvé cette question sur Stackoverflow, stackoverflow.com/questions/20319118/ ... c'est exactement le même problème que j'ai, mais malheureusement pas de réponse :(
tcode
Comment vos composants OWIN sont-ils initialisés?
Derek Van Cuyk
J'ai récemment eu un problème comme celui-ci; J'espère que cette solution aidera: stackoverflow.com/questions/34537475/…
Alexandru

Réponses:

172

Essaye ça:

[Authorize]
public ActionResult SomeAction()
{
    var identity = (ClaimsIdentity)User.Identity;
    IEnumerable<Claim> claims = identity.Claims;
    ...
}
Darin Dimitrov
la source
Merci de votre aide. J'ai utilisé votre réponse suggérée dans une action au sein d'un contrôleur pour essayer d'accéder aux valeurs des revendications, cependant, l'identité I.Claims est toujours NULL (voir la question mise à jour avec capture d'écran). D'autres idées? J'apprécie ton aide.
tcode
Non, désolé, je n'ai pas d'autres idées. Cela a toujours fonctionné pour moi.
Darin Dimitrov
Désolé, une dernière question. Dois-je créer ma propre classe personnalisée ClaimsAuthenticationManager et Application_PostAuthenticateRequest () dans Global.asax comme ce dotnetcodr.com/2013/02/25/... avant que mon code ci-dessus ne fonctionne? Merci encore.
tcode
7
Jusqu'à ce que vous autorisiez pour la première fois, vous n'y aurez pas accès avant votre méthode de connexion, c'est pourquoi l'OP ne le voit pas à ce moment-là. Vous devez charger manuellement à ce moment si vous le souhaitez dans la méthode de connexion.
Adam Tuliper - MSFT
Je travaille avec asp.net core et je cherche le moyen d'obtenir une photo de profil LinkedIn pendant plus de 2 heures. Je suis coincé, je suis fatigué, je veux abandonner jusqu'à ce que je vois ta réponse. Je veux dire merci des millions de fois ... +1
Vayne
36

Vous pouvez également faire ceci:

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

Mettre à jour

Pour fournir des explications supplémentaires conformément aux commentaires.

Si vous créez des utilisateurs dans votre système comme suit:

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

Vous devriez automatiquement remplir certaines réclamations relatives à votre identité.

Pour ajouter des revendications personnalisées après l'authentification d'un utilisateur, vous pouvez procéder comme suit:

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

Les revendications peuvent être lues comme Darin a répondu ci-dessus ou comme je l'ai fait.

Les revendications sont conservées lorsque vous appelez ci-dessous en transmettant l'identité:

AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = persistCookie }, identity);
hutchonoïde
la source
Merci, mais cela ne fonctionne toujours pas pour moi. Pouvez-vous voir ma question mise à jour? Aussi, une dernière question. Dois-je créer ma propre classe personnalisée ClaimsAuthenticationManager et Application_PostAuthenticateRequest () dans Global.asax comme ce dotnetcodr.com/2013/02/25/... avant que mon code ci-dessus ne fonctionne? Merci encore pour votre aide.
tcode
Salut, je jetterai un coup d'oeil quand je serai de retour sur un PC.
hutchonoid
merci, vraiment apprécier. À un stade où cela commence à me faire craquer :)
tcode
@tgriffiths Bonjour, j'ai ajouté une mise à jour pour vous. J'espère fournir un peu plus d'informations. Bonne chance. :)
hutchonoid
malheureusement, je n'utilise pas le code intégré Entity Framework First, par exemple, UserManager, etc. Mais merci pour votre contribution. À votre santé.
tcode
30

Je crée ma propre classe étendue pour voir ce dont j'ai besoin, donc quand j'en ai besoin dans mon contrôleur ou ma vue, je n'ajoute que l'utilisation à mon espace de noms quelque chose comme ceci:

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 ....
    {
      .....
    }
}

Dans mon contrôleur:

using XXX.CodeHelpers.Extended;

var claimAddress = User.GetAddress();

Dans mon rasoir:

@using DinexWebSeller.CodeHelpers.Extended;

@User.GetFullName()
Jésus Padilla
la source
8
return claim?.Value;parce que pourquoi pas
Halter
17

Ceci est une alternative si vous ne souhaitez pas utiliser les revendications tout le temps. Jetez un œil à ce tutoriel de Ben Foster.

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

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

}

Ensuite, vous pouvez ajouter un contrôleur de base.

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

Dans votre contrôleur, vous feriez:

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

Pour approfondir la réponse de Darin, vous pouvez accéder à vos revendications spécifiques en utilisant la méthode FindFirst :

var identity = (ClaimsIdentity)User.Identity;
var role = identity.FindFirst(ClaimTypes.Role).Value;
Eric Bridges
la source
Ou celui-ci trop string myValue = identity.FindFirstValue ("MyClaimType");
Juan Carlos Puerto
Que se passe-t-il si FindFirst ne trouve aucune revendication de type "rôle"? exception nulle?
Phil
10

Vous pouvez également le faire.

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

N'oubliez pas que pour interroger IEnumerable, vous devez référencer system.linq.
Cela vous donnera l'objet d'extension nécessaire pour faire:

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

La version la plus courte et simplifiée de la réponse @Rosdi Kasim'd est

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

Claimname est la revendication que vous souhaitez récupérer, c.-à-d. si vous recherchez une revendication "StreedAddress", la réponse ci-dessus sera comme ceci

string claimvalue = ((System.Security.Claims.ClaimsIdentity)User.Identity).
    FindFirst("StreedAddress").Value;
noman zafar
la source
fournir l'exemple "claimvalue" m'a fait gagner du temps. Merci
Nour Lababidi
6
Request.GetOwinContext().Authentication.User.Claims

Cependant, il est préférable d'ajouter les revendications à l'intérieur de la méthode "GenerateUserIdentityAsync", en particulier si regenerateIdentity dans Startup.Auth.cs est activé.

Basil Banbouk
la source
La GenerateUserIdentityAsyncsuggestion était génial, je l' ai totalement a oublié. Merci beaucoup Basil.
timmi4sa
2

Selon la classe ControllerBase, vous pouvez obtenir les revendications de l'utilisateur exécutant l'action.

entrez la description de l'image ici

voici comment vous pouvez le faire en 1 ligne.

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

Je l'ai utilisé comme ça dans mon contrôleur de base. Juste partager pour prêt à l'emploi.

    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
la source