Dados do usuário de identidade de declarações de acesso MVC 5


119

Estou desenvolvendo um aplicativo da web MVC 5 usando a abordagem Entity Framework 5 Database First . Estou usando OWIN para autenticação de usuários. Abaixo mostra o meu método de login no meu controlador de conta.

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 você pode ver, estou criando um ClaimIdentity e adicionando várias declarações a ele e, em seguida, passando-o para o OWIN usando o AuthenticationManager para fazer o login.

O problema que estou tendo é que não tenho certeza de como acessar as declarações no resto do meu aplicativo, seja nos controladores ou nas visualizações do Razor.

Eu tentei a abordagem listada neste tutorial

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

Por exemplo, eu tentei isso no meu código do controlador na tentativa de obter acesso aos valores passados ​​para as reivindicações, no entanto, o usuário.Claim é igual a nulo

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

Talvez eu esteja faltando alguma coisa aqui.

ATUALIZAR

Com base na resposta de Darin, adicionei seu código, mas ainda não consigo ver o acesso às Reivindicações. Por favor, veja a captura de tela abaixo mostrando o que eu vejo quando passei o mouse sobre a identidade. Reivindicações.

insira a descrição da imagem aqui


Você pode confirmar se o cookie é enviado de volta pelo navegador? Talvez suas configurações de segurança exijam SSL?
mínimo privilégio

@leastprivilege Obrigado, vou dar uma olhada nisso agora. Encontrei esta pergunta no Stackoverflow, stackoverflow.com/questions/20319118/… é exatamente o mesmo problema que estou tendo, mas infelizmente nenhuma resposta para ele :(
tcode

Como seus componentes OWIN são inicializados?
Derek Van Cuyk 01 de

Recentemente, tive um problema como este; Espero que esta solução ajude: stackoverflow.com/questions/34537475/…
Alexandru

Respostas:


172

Experimente isto:

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

Obrigado pela ajuda. Usei sua resposta sugerida em uma ação dentro de um controlador para tentar acessar os valores de reivindicações, no entanto, I identity.Claims ainda é NULL (consulte a pergunta atualizada com a captura de tela). Alguma outra ideia? Eu aprecio sua ajuda.
tcode

Não, desculpe, não tenho outras idéias. Isto sempre funcionou para mim.
Darin Dimitrov

Desculpe, uma última pergunta. Preciso criar minha própria classe ClaimsAuthenticationManager personalizada e Application_PostAuthenticateRequest () em Global.asax como este dotnetcodr.com/2013/02/25/… antes que meu código acima funcione? Obrigado novamente.
tcode

7
Até que você autorize pela primeira vez, você não terá acesso a isso até depois de seu método de login, e é por isso que o OP não o vê naquele momento. Você deve carregar manualmente neste momento se quiser no método Login.
Adam Tuliper - MSFT

Estou trabalhando com o asp.net core e procurando uma maneira de obter a foto do perfil do LinkedIn durante mais de 2 horas. Estou preso, estou cansado, quero desistir até ver sua resposta. Quero agradecer milhões de vezes ... +1
Vayne

36

Você também pode fazer isso:

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

Atualizar

Para fornecer mais explicações de acordo com os comentários.

Se você estiver criando usuários em seu sistema da seguinte maneira:

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

Você deve ter automaticamente algumas reivindicações preenchidas relacionadas à sua identidade.

Para adicionar declarações personalizadas após a autenticação de um usuário, você pode fazer isso da seguinte maneira:

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

As afirmações podem ser lidas como Darin respondeu acima ou como eu respondi.

As reivindicações são mantidas quando você chama abaixo, passando a identidade em:

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

Obrigado, mas isso ainda não funciona para mim. Você pode ver minha pergunta atualizada? Além disso, uma última pergunta. Preciso criar minha própria classe ClaimsAuthenticationManager personalizada e Application_PostAuthenticateRequest () em Global.asax como este dotnetcodr.com/2013/02/25/… antes que meu código acima funcione? Obrigado novamente por sua ajuda.
tcode

Olá, darei uma olhada quando voltar ao PC.
hutchonoid

obrigado, realmente aprecio isso. Em um estágio em que isso está começando a me quebrar :)
tcode

@tgriffiths Olá, adicionei uma atualização para você. Espero fornecer um pouco mais de informação. Boa sorte. :)
hutchonoid

infelizmente, não estou usando o Entity Framework Code First, por exemplo, UserManager etc. Mas obrigado por sua contribuição. Felicidades.
tcode

30

Eu faço minha própria classe estendida para ver o que eu preciso, então quando eu preciso em meu controlador ou meu View, eu apenas adiciono o using ao meu namespace algo assim:

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

No meu controlador:

using XXX.CodeHelpers.Extended;

var claimAddress = User.GetAddress();

Na minha navalha:

@using DinexWebSeller.CodeHelpers.Extended;

@User.GetFullName()

8
return claim?.Value;porque por que não
Halter

17

Essa é uma alternativa se você não quiser usar reivindicações o tempo todo. Dê uma olhada neste tutorial de Ben Foster.

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

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

}

Então você pode adicionar um controlador básico.

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

Em seu controlador, você faria:

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

12

Para aprofundar a resposta de Darin, você pode obter suas reivindicações específicas usando o método FindFirst :

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

Ou este também string myValue = identity.FindFirstValue ("MyClaimType");
Juan Carlos Puerto,

O que acontecerá se FindFirst não encontrar nenhuma declaração com o tipo "função"? exceção nula?
Phil

10

Você também pode fazer isso.

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

8

Lembre-se de que, para consultar o IEnumerable, você precisa fazer referência a system.linq.
Ele fornecerá o objeto de extensão necessário para fazer:

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

7

a versão mais curta e simplificada da resposta de @Rosdi Kasim'd é

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

Claimname é a reivindicação que você deseja recuperar, ou seja, se você estiver procurando por uma reivindicação "StreedAddress", a resposta acima será assim

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

fornecer o exemplo "valor de reivindicação" economizou meu tempo. Obrigado
Nour Lababidi

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

No entanto, é melhor adicionar as declarações dentro do método "GenerateUserIdentityAsync", especialmente se regenerateIdentity no Startup.Auth.cs estiver habilitado.


Essa GenerateUserIdentityAsyncfoi uma sugestão incrível, eu a ignorei totalmente. Muito obrigado, Basil.
timmi4sa

2

De acordo com a classe ControllerBase, você pode obter as declarações para o usuário que está executando a ação.

insira a descrição da imagem aqui

veja como você pode fazer isso em 1 linha.

var claims = User.Claims.ToList();

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

0

Eu usei assim no meu controlador de base. Apenas compartilhando para pronto para 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();
    }
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.