ASP.NET MVC 5 - Identidade. Como obter o ApplicationUser atual

237

Eu tenho uma entidade Article no meu projeto que possui a ApplicationUserpropriedade nomeada Author. Como posso obter o objeto completo do log atualmente ApplicationUser? Ao criar um novo artigo, tenho que definir a Authorpropriedade Articlecomo atual ApplicationUser.

No antigo mecanismo de associação, era simples, mas, na nova abordagem de identidade, não sei como fazer isso.

Eu tentei fazer assim:

  • Adicione a instrução using para extensões de identidade: using Microsoft.AspNet.Identity;
  • Então eu tento obter o usuário atual: ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == User.Identity.GetUserId());

Mas eu recebo a seguinte exceção:

O LINQ to Entities não reconhece o método 'System.String GetUserId (System.Security.Principal.IIdentity)' e esse método não pode ser convertido em uma expressão de armazenamento. Source = EntityFramework

Ellbar
fonte

Respostas:

448

Você não precisa consultar o banco de dados diretamente para o ApplicationUser atual.

Isso introduz uma nova dependência de ter um contexto extra para iniciantes, mas daqui para frente as tabelas do banco de dados do usuário mudam (3 vezes nos últimos 2 anos), mas a API é consistente. Por exemplo, a userstabela agora é chamada AspNetUsersno Identity Framework e os nomes de vários campos de chave primária são alterados, de modo que o código em várias respostas não funcionará mais como está .

Outro problema é que o acesso OWIN subjacente ao banco de dados usará um contexto separado, para que alterações de acesso SQL separado possam produzir resultados inválidos (por exemplo, não vendo alterações feitas no banco de dados). Novamente, a solução é trabalhar com a API fornecida e não tentar contorná- la.

A maneira correta de acessar o objeto de usuário atual na identidade do ASP.Net (nesta data) é:

var user = UserManager.FindById(User.Identity.GetUserId());

ou, se você tiver uma ação assíncrona, algo como:

var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());

FindByIdrequer que você tenha a seguinte instrução using para que os UserManagermétodos não assíncronos estejam disponíveis (eles são métodos de extensão para o UserManager, portanto, se você não incluir isso, verá apenas FindByIdAsync):

using Microsoft.AspNet.Identity;

Se você não estiver em um controlador (por exemplo, você estiver usando injeção IOC), o ID do usuário será recuperado na íntegra de:

System.Web.HttpContext.Current.User.Identity.GetUserId();

Se você não estiver no controlador de conta padrão, precisará adicionar o seguinte (como exemplo) ao seu controlador:

1. Adicione estas duas propriedades:

    /// <summary>
    /// Application DB context
    /// </summary>
    protected ApplicationDbContext ApplicationDbContext { get; set; }

    /// <summary>
    /// User manager - attached to application DB context
    /// </summary>
    protected UserManager<ApplicationUser> UserManager { get; set; }

2. Adicione isso no construtor do Controlador:

    this.ApplicationDbContext = new ApplicationDbContext();
    this.UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(this.ApplicationDbContext));

Atualização de março de 2015

Nota: A atualização mais recente da estrutura de identidade altera uma das classes subjacentes usadas para autenticação. Agora você pode acessá-lo no Contexto Owin do atual HttpContent.

ApplicationUser user = System.Web.HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(System.Web.HttpContext.Current.User.Identity.GetUserId());

Termo aditivo:

Ao usar o EF e o Identity Framework com o Azure, em uma conexão remota com o banco de dados (por exemplo, teste de host local com o banco de dados do Azure), você pode acertar aleatoriamente o temido "erro: 19 - a conexão física não é utilizável". Como a causa está oculta no Identity Framework, onde você não pode adicionar novas tentativas (ou o que parece estar faltando .Include(x->someTable)), é necessário implementar uma customização SqlAzureExecutionStrategyno seu projeto.

Gone Coding
fonte
5
@ TBA - obrigado, percebi depois que é um método de extensão. Precisa adicionar Microsoft.AspNet.Identity usando. obrigado novamente
Sentinela
2
Digite ou namesapce UserStore não poderia ser found.I adicionado usando Microsft.AspNet.Indentity
Wasfa
2
@Zapnologica: Parece uma nova pergunta (sugiro que você a publique). Você pode estender a ApplicationUserclasse (específica do aplicativo) e a AspNetUserstabela em paralelo, e elas fornecerão novos campos. Novamente: Não acerte o banco de dados diretamente! :)
Gone Coding
2
@ LifeH2O: O ApplicationUser retornado por FindById é sua classe, completa com suas propriedades extras. Por favor tente.
Gone Coding
1
Esperando sua nova Solução: P
Anup Sharma
60

Meu erro, eu não deveria ter usado um método dentro de uma consulta LINQ.

Código correto:

using Microsoft.AspNet.Identity;


string currentUserId = User.Identity.GetUserId();
ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == currentUserId);
Ellbar
fonte
2
User.Identiy.GetUserId não existe para mim. é esse método personalizado? Eu só entro em User.Identity
Gerrie Pretorius
9
Deixa pra lá ... você precisa do "using Microsoft.AspNet.Identity;" para esse método estar lá.
Gerrie Pretorius
4
Apenas uma observação, o objeto Usuário é visível apenas nos Controladores.
Miro J.
8
Certamente você deve usar UserManagermétodos e não atingir o banco de dados diretamente?
Gone Coding
3
@ Josh Bjelovuk: Nunca acesse um banco de dados diretamente quando uma API estiver disponível. Isso introduz uma nova dependência de ter um contexto extra para iniciantes, mas daqui para frente as tabelas do banco de dados do usuário mudam (3 vezes nos últimos 2 anos), mas a API é consistente.
Gone Coding
33

Está nos comentários das respostas, mas ninguém postou isso como a solução real.

Você só precisa adicionar uma instrução using na parte superior:

using Microsoft.AspNet.Identity;
rtpHarry
fonte
2
Eu vim aqui com essa exceção, resolvi com isso using. Vendo como 15k pessoas visitaram a pergunta que eu percebi que era uma resposta útil :)
rtpHarry
2
@TrueBlueAussie, apesar de não ser uma resposta direta à pergunta dos OPs, acho que mencionar o uso é uma adição muito útil.
StuartQ
1
Para maior clareza, é porque .GetUserId()é um método de extensão
FSCKur
11

O código de Ellbar funciona! Você só precisa adicionar usando.

1 - using Microsoft.AspNet.Identity;

E ... o código de Ellbar:

2 - string currentUserId = User.Identity.GetUserId(); ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == currentUserId);

Com este código (in currentUser), você trabalha os dados gerais do usuário conectado, se desejar dados extras ... consulte este link

Diego Borges
fonte
5
Pode "funcionar", mas certamente não é recomendável ignorar a API fornecida e acessar o banco de dados diretamente. Se você usou a API, não precisaria de trabalho extra para obter os dados extras , pois eles já estariam no ApplicationUserobjeto
Gone Coding
Concordo! No entanto, recorri dessa maneira porque eu já tinha um sistema em funcionamento hoje, com uma execução no banco de dados e preciso de uma solução simples para resolver esse problema! Certamente, em um sistema inicial, eu colocaria objetos em suas classes e identidades apropriadas.
Diego Borges
6

A partir do ASP.NET Identity 3.0.0, isso foi refatorado para

//returns the userid claim value if present, otherwise returns null
User.GetUserId();
Seth IK
fonte
6
ApplicationDbContext context = new ApplicationDbContext();
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
ApplicationUser currentUser = UserManager.FindById(User.Identity.GetUserId());

string ID = currentUser.Id;
string Email = currentUser.Email;
string Username = currentUser.UserName;
Majid joghataey
fonte
3

Para o MVC 5, basta olhar dentro do método EnableTwoFactorAuthentication do ManageController no andaime do modelo WebApplication, sendo feito aqui:

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> EnableTwoFactorAuthentication()
        {
            await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), true);
            var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
            if (user != null)
            {
                await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
            }
            return RedirectToAction("Index", "Manage");
        }

A resposta está aí, como sugerido pela própria Microsoft:

var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());

Ele terá todas as propriedades adicionais definidas na classe ApplicationUser.

Paceman
fonte
5
Já coberto. Por favor verifique que uma resposta idêntica não estiver publicado (ou adicionar um comentário a uma resposta já existente) :)
ida Codificação
3

No momento, o modelo de projeto asp.mvc cria um controlador de conta que obtém o gerenciador de usuários da seguinte maneira:

HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>()

O seguinte funciona para mim:

ApplicationUser user = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(User.Identity.GetUserId());
Holger Thiemann
fonte
0

Eu estava disponível com sucesso para obter o Usuário do aplicativo seguindo o código

var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
            var user = manager.FindById(User.Identity.GetUserId());
            ApplicationUser EmpUser = user;
Abdul Hannan
fonte
0

No caso de alguém estar trabalhando com Identityusuários web forms, eu consegui:

var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var user = manager.FindById(User.Identity.GetUserId());
Jamshaid Kamran
fonte