Preciso fazer algo bastante simples: no meu aplicativo ASP.NET MVC, quero definir um IIdentity / IPrincipal personalizado. O que for mais fácil / mais adequado. Eu quero estender o padrão para que eu possa chamar algo como User.Identity.Id
e User.Identity.Role
. Nada extravagante, apenas algumas propriedades extras.
Eu li vários artigos e perguntas, mas sinto que estou dificultando o que realmente é. Eu pensei que seria fácil. Se um usuário fizer logon, desejo definir uma identidade II personalizada. Então eu pensei, vou implementar Application_PostAuthenticateRequest
no meu global.asax. No entanto, isso é chamado em todas as solicitações, e eu não quero fazer uma chamada ao banco de dados em todas as solicitações que solicitariam todos os dados do banco de dados e colocassem um objeto IPrincipal personalizado. Isso também parece muito desnecessário, lento e no lugar errado (fazendo chamadas de banco de dados lá), mas eu posso estar errado. Ou de onde mais esses dados viriam?
Por isso, pensei que, sempre que um usuário efetua login, posso adicionar algumas variáveis necessárias em minha sessão, adicionadas à IIdentity personalizada no Application_PostAuthenticateRequest
manipulador de eventos. No entanto, o meu Context.Session
está null
lá, de modo que também não é o caminho a percorrer.
Estou trabalhando nisso há um dia e sinto que estou perdendo alguma coisa. Isso não deve ser muito difícil de fazer, certo? Também estou um pouco confuso com todas as coisas (semi) relacionadas que acompanham isso. MembershipProvider
, MembershipUser
, RoleProvider
, ProfileProvider
, IPrincipal
, IIdentity
, FormsAuthentication
.... Eu sou o único que acha tudo isso muito confuso?
Se alguém pudesse me dizer uma solução simples, elegante e eficiente para armazenar alguns dados extras em uma identidade sem todo o fuzz extra ... isso seria ótimo! Eu sei que existem perguntas semelhantes no SO, mas se a resposta que eu preciso está aí, eu devo ter esquecido.
MemberShip...
,Principal
,Identity
. O ASP.NET deve facilitar, simplificar e, no máximo, duas abordagens para lidar com a autenticação.Respostas:
Aqui está como eu faço isso.
Decidi usar o IPrincipal em vez do IIdentity porque significa que não preciso implementar o IIdentity e o IPrincipal.
Crie a interface
CustomPrincipal
CustomPrincipalSerializeModel - para serializar informações personalizadas no campo de dados do usuário no objeto FormsAuthenticationTicket.
Método de logon - configurando um cookie com informações personalizadas
Global.asax.cs - Lendo o cookie e substituindo o objeto HttpContext.User, isso é feito substituindo PostAuthenticateRequest
Acesso às visualizações do Razor
e no código:
Eu acho que o código é auto-explicativo. Se não for, me avise.
Além disso, para tornar o acesso ainda mais fácil, você pode criar um controlador base e substituir o objeto Usuário retornado (HttpContext.User):
e depois, para cada controlador:
que permitirá acessar campos personalizados em códigos como este:
Mas isso não funcionará dentro das visualizações. Para isso, você precisará criar uma implementação personalizada do WebViewPage:
Crie um tipo de página padrão em Views / web.config:
e nas visualizações, você pode acessá-lo assim:
fonte
Thread.CurrentPrincipal
aApplication_PostAuthenticateRequest
para que ele funcione como ele não dependemHttpContext.Current.User
FormsAuthentication.SignOut();
funciona bem para mim.Não posso falar diretamente para o ASP.NET MVC, mas para o ASP.NET Web Forms, o truque é criar
FormsAuthenticationTicket
e criptografá-lo em um cookie depois que o usuário for autenticado. Dessa forma, você só precisa chamar o banco de dados uma vez (ou o AD ou o que estiver usando para executar sua autenticação) e cada solicitação subsequente será autenticada com base no ticket armazenado no cookie.Um bom artigo sobre isso:
http://www.ondotnet.com/pub/a/dotnet/2004/02/02/effectiveformsauth.html(link quebrado)Editar:
Como o link acima está quebrado, eu recomendaria a solução de LukeP em sua resposta acima: https://stackoverflow.com/a/10524305 - Eu também sugeriria que a resposta aceita fosse alterada para essa.
Edição 2: Uma alternativa para o link quebrado: https://web.archive.org/web/20120422011422/http://ondotnet.com/pub/a/dotnet/2004/02/02/effectiveformsauth.html
fonte
Cache
como umSession
substituto para manter os dados no servidor. Alguém pode me dizer se esta é uma abordagem falho?Aqui está um exemplo para fazer o trabalho. O bool isValid é definido olhando para algum armazenamento de dados (digamos, sua base de dados do usuário). UserID é apenas um ID que estou mantendo. Você pode adicionar informações adicionais, como endereço de email, aos dados do usuário.
no golax asax, adicione o seguinte código para recuperar suas informações
Quando você usar as informações posteriormente, poderá acessar seu principal personalizado da seguinte maneira.
isso permitirá que você acesse informações personalizadas do usuário.
fonte
O MVC fornece o método OnAuthorize que trava nas suas classes de controlador. Ou você pode usar um filtro de ação personalizado para executar a autorização. O MVC facilita bastante a execução. Eu publiquei um post sobre isso aqui. http://www.bradygaster.com/post/custom-authentication-with-mvc-3.0
fonte
Aqui está uma solução se você precisar conectar alguns métodos ao @User para usar em suas visualizações. Nenhuma solução para qualquer personalização séria de associação, mas se a pergunta original fosse necessária apenas para visualizações, talvez isso fosse suficiente. O abaixo foi usado para verificar uma variável retornada de um filtro de autor, usada para verificar se alguns links devem ser apresentados ou não (não para qualquer tipo de lógica de autorização ou concessão de acesso).
Em seguida, basta adicionar uma referência nas áreas web.config e chamá-la como abaixo na exibição.
fonte
Baseado em resposta de LukeP , adicione alguns métodos para configurar
timeout
erequireSSL
colaborarWeb.config
.Os links de referências
Códigos modificados de LukeP
1, definido com
timeout
baseWeb.Config
. O FormsAuthentication.Timeout obterá o valor do tempo limite, definido em web.config. Embrulhei o seguinte para ser uma função, que retorna umaticket
volta.2, Configure o cookie para ser seguro ou não, com base na
RequireSSL
configuração.fonte
Tudo bem, então eu sou um cryptkeeper sério arrastando essa pergunta muito antiga, mas há uma abordagem muito mais simples disso, que foi abordada por @Baserz acima. E isso é usar uma combinação de métodos de extensão C # e cache (NÃO use session).
De fato, a Microsoft já forneceu várias dessas extensões no
Microsoft.AspNet.Identity.IdentityExtensions
espaço para nome. Por exemplo,GetUserId()
é um método de extensão que retorna o ID do usuário. Há tambémGetUserName()
eFindFirstValue()
, que retorna declarações com base no IPrincipal.Então você só precisa incluir o espaço para nome e chamar
User.Identity.GetUserName()
para obter o nome de usuário conforme configurado pela identidade do ASP.NET.Não tenho certeza se isso está em cache, pois a antiga identidade do ASP.NET não é de código aberto e não me preocupei em fazer a engenharia reversa. No entanto, se não for, você poderá escrever seu próprio método de extensão, que armazenará esse resultado em cache por um período específico de tempo.
fonte
IsUserAdministrator
ouUserEmail
etc.? Você está pensandoHttpRuntime.Cache
?Como um complemento ao código LukeP para usuários de Web Forms (não MVC), se você deseja simplificar o acesso no código por trás de suas páginas, basta adicionar o código abaixo a uma página base e derivar a página base em todas as suas páginas:
Portanto, no seu código por trás, você pode simplesmente acessar:
O que estou perdendo em um cenário de formulário da Web é como obter o mesmo comportamento no código não vinculado à página, por exemplo, em httpmodules , devo sempre adicionar uma em cada classe ou existe uma maneira mais inteligente de obter isso?
Obrigado por suas respostas e agradecer a LukeP desde que eu usei seus exemplos como base para o meu usuário personalizada (que agora tem
User.Roles
,User.Tasks
,User.HasPath(int)
,User.Settings.Timeout
e muitas outras coisas boas)fonte
Tentei a solução sugerida por LukeP e constatei que ela não suporta o atributo Autorizar. Então, eu modifiquei um pouco.
E finalmente em Global.asax.cs
Agora eu posso acessar os dados em visualizações e controladores simplesmente chamando
Para sair, eu ligo
onde AuthManager é
fonte