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.