MVC 5 Access Claims Identity User Data


119

Sto sviluppando un'applicazione Web MVC 5 utilizzando l' approccio Database First di Entity Framework 5 . Sto usando OWIN per l'autenticazione degli utenti. Di seguito viene mostrato il mio metodo di accesso all'interno del controller dell'account.

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

Come puoi vedere, sto creando una ClaimsIdentity e aggiungendovi diverse attestazioni, quindi passandola a OWIN utilizzando AuthenticationManager per eseguire l'accesso.

Il problema che sto riscontrando è che non sono sicuro di come accedere alle attestazioni nel resto della mia applicazione, in Controller o in Razor Views.

Avevo provato l'approccio elencato in questo tutorial

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

Ad esempio, ho provato questo nel codice del controller nel tentativo di ottenere l'accesso ai valori passati nelle attestazioni, tuttavia, l'utente. Reclami è uguale a null

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

Forse mi manca qualcosa qui.

AGGIORNARE

Sulla base della risposta di Darin, ho aggiunto il suo codice ma non riesco ancora a vedere l'accesso ai reclami. Si prega di vedere lo screenshot qui sotto che mostra ciò che vedo quando si passa con il mouse sull'identità.

inserisci qui la descrizione dell'immagine


Puoi confermare che il cookie viene rispedito dal browser? Forse le tue impostazioni di sicurezza richiedono SSL?
leastprivilege

@leastprivilege Grazie, lo esaminerò ora. Ho trovato questa domanda su Stackoverflow, stackoverflow.com/questions/20319118/… è lo stesso identico problema che sto avendo, ma sfortunatamente nessuna risposta :(
tcode

Come vengono inizializzati i componenti OWIN?
Derek Van Cuyk

Recentemente ho avuto un problema come questo; Spero che questa soluzione aiuti: stackoverflow.com/questions/34537475/…
Alexandru

Risposte:


172

Prova questo:

[Authorize]
public ActionResult SomeAction()
{
    var identity = (ClaimsIdentity)User.Identity;
    IEnumerable<Claim> claims = identity.Claims;
    ...
}

Grazie per l'aiuto. Ho usato la tua risposta suggerita in un'azione all'interno di un controller per provare ad accedere ai valori di Claims, tuttavia, I identity.Claims è ancora NULL (vedi domanda aggiornata con screenshot). Altre idee? Apprezzo il vostro aiuto.
tcode

No, scusa non ho altre idee. Questo ha sempre funzionato per me.
Darin Dimitrov

Scusa, un'ultima domanda. Devo creare la mia classe ClaimsAuthenticationManager personalizzata e Application_PostAuthenticateRequest () in Global.asax come questo dotnetcodr.com/2013/02/25/… prima che il mio codice sopra funzioni? Grazie ancora.
tcode

7
Fino a quando non autorizzi per la prima volta, non avrai accesso a questo fino a dopo il tuo metodo di accesso, motivo per cui l'OP non lo vede in quel momento. È necessario caricare manualmente in questo momento se lo si desidera nel metodo di accesso.
Adam Tuliper - MSFT

Sto lavorando con asp.net core e sto cercando il modo per ottenere l'immagine del profilo LinkedIn per più di 2 ore. Sono bloccato, sono stanco, voglio arrendermi finché non vedo la tua risposta. Voglio dire grazie milioni di volte ... +1
Vayne

36

Puoi anche farlo:

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

Aggiornare

Per fornire ulteriori spiegazioni come da commenti.

Se stai creando utenti all'interno del tuo sistema come segue:

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

Dovresti avere automaticamente alcuni reclami popolati relativi alla tua identità.

Per aggiungere attestazioni personalizzate dopo che un utente si è autenticato, puoi procedere come segue:

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

Le affermazioni possono essere rilette come Darin ha risposto sopra o come ho fatto io.

Le attestazioni vengono mantenute quando chiami di seguito passando l'identità in:

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

Grazie, ma ancora questo non funziona per me. Riesci a vedere la mia domanda aggiornata? Inoltre, un'ultima domanda. Devo creare la mia classe ClaimsAuthenticationManager personalizzata e Application_PostAuthenticateRequest () in Global.asax come questo dotnetcodr.com/2013/02/25/… prima che il mio codice sopra funzioni? Grazie ancora per il vostro aiuto.
tcode

Ciao, darò un'occhiata quando tornerò su un PC.
hutchonoid

grazie, lo apprezzo davvero. In una fase in cui questo sta iniziando a farmi
arrabbiare

@tgriffiths Ciao, ho aggiunto un aggiornamento per te. Si spera di fornire qualche informazione in più. In bocca al lupo. :)
hutchonoid

sfortunatamente non sto usando il codice integrato di Entity Framework First, ad esempio UserManager, ecc. Ma grazie per il tuo contributo. Saluti.
tcode

30

Creo la mia classe estesa per vedere di cosa ho bisogno, quindi quando ho bisogno nel mio controller o nella mia vista, aggiungo solo l'uso al mio spazio dei nomi qualcosa del genere:

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

Nel mio controller:

using XXX.CodeHelpers.Extended;

var claimAddress = User.GetAddress();

Nel mio rasoio:

@using DinexWebSeller.CodeHelpers.Extended;

@User.GetFullName()

8
return claim?.Value;perché no
Halter

17

Questa è un'alternativa se non vuoi utilizzare le attestazioni tutto il tempo. Dai un'occhiata a questo tutorial di Ben Foster.

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

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

}

Quindi puoi aggiungere un controller di base.

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

Nel tuo controller, faresti:

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

12

Per toccare ulteriormente la risposta di Darin, puoi accedere alle tue affermazioni specifiche utilizzando il metodo FindFirst :

var identity = (ClaimsIdentity)User.Identity;
var role = identity.FindFirst(ClaimTypes.Role).Value;

O anche questa stringa myValue = identity.FindFirstValue ("MyClaimType");
Juan Carlos Puerto

Cosa succede se FindFirst non trova alcuna rivendicazione con il tipo "ruolo"? eccezione nulla?
Phil

10

Puoi anche farlo.

IEnumerable<Claim> claims = ClaimsPrincipal.Current.Claims;

8

Ricorda che per interrogare IEnumerable devi fare riferimento a system.linq.
Ti darà l'oggetto di estensione necessario per fare:

CaimsList.FirstOrDefault(x=>x.Type =="variableName").toString();

7

la versione più breve e semplificata della risposta di @Rosdi Kasim è

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

Claimname è il reclamo che vuoi recuperare cioè se stai cercando il reclamo "StreedAddress" allora la risposta di cui sopra sarà come questa

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

fornendo l'esempio "claimvalue" mi ha fatto risparmiare tempo. Grazie
Nour Lababidi

6
Request.GetOwinContext().Authentication.User.Claims

Tuttavia è meglio aggiungere le attestazioni all'interno del metodo "GenerateUserIdentityAsync", soprattutto se rigenerateIdentity in Startup.Auth.cs è abilitato.


È GenerateUserIdentityAsyncstato un suggerimento fantastico, l'ho completamente trascurato. Grazie mille Basil.
timmi4sa

2

Secondo la classe ControllerBase, puoi ottenere le attestazioni per l'utente che esegue l'azione.

inserisci qui la descrizione dell'immagine

ecco come puoi farlo in 1 riga.

var claims = User.Claims.ToList();

1
var claim = User.Claims.FirstOrDefault(c => c.Type == "claim type here");

0

L'ho usato così nel mio controller di base. Basta condividere per essere pronto per l'uso.

    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();
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.