Categorias
ASP.NET formulários de autenticação com roles
A autenticação com não permite autenticação com roles. Este artigo explica como implementar a autenticação com roles.
Aspectos básicos da autenticação forms.
A autenticação baseada em forms é bastante útil no ASP.NET. Ao invés de escrevermos nossos próprios processos de autenticação, podemos simplesmente mudar o web.config sob system.web ....
<authentication mode="Forms"/>
<forms
name="MyWebsiteCookieName"
loginUrl="/Login.aspx"
protection="All"
timeout="180"
/>
</authentication>
- O modo de autenticação é configurado para forms.
- Uma URL é fornecida para o ASP.NET saber para onde redirecionar as pessoas que precisam logar-se.
- Um tempo limite é especificado em minutos. Este é o "time since last request", não o "time since login". Se um login é indicado para ser persistente (descrito mais tarde) esta configuração é ignorada.
- Um método de proteção é indicado para o cookie.
Depois, eu quis especificar uma pasta cujo acesso é restrito a pessoas que já fizeram o login. Para fazer isto, digitei o seguinte código no arquivo web.config ( sob <configuration>):
<location path="Members">
<system.web>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
</location>
Isto diz ao ASP.NET que o caminho "/Members" (a barra / sempre está implícita) deve negar o acesso a todos os usuários desconhecidos. Quando alguém tenta acessar uma página em /Members, será redirecionado para a URL login.aspx que você especificou no web.config.
Este form login.aspx deve solicitar quaisquer credenciais que você quiser (nome de usuário e senha, por exemplo) e validá-las. Logo que tenham sido validadas, só é preciso executar o seguinte código para redirecionar o usuário de volta para a página que ele estava tentando acessar inicialmente.
System.Web.Security.FormsAuthentication.RedirectFromLoginPage (UserId, false);
O userID é o identificador único para o usuário atual (username), e o segundo parâmetro booleano indica se este deveria ser um cookie de segurança persistente ou temporário (que expira desde a última página pedida), conforme mencionado anteriormente.
Roles
Foi nesse momento que eu percebi que precisava de uma pasta especial /Admin. Essa pasta só deve ser acessada por administradores, e não por usuários normais. Para isto, eu obviamente precisava de roles no web.config (<configuration> abaixo), da seguinte maneira:
<location path="Admin">
<system.web>
<authorization>
<allow roles="Admin"/>
<deny users="*"/>
</authorization>
</system.web>
</location>
Nota: A ordem das ações allow/deny é importante. Se você negar * (todos os usuários) antes de permitir o role Admin, ninguém terá acesso à pasta.
O problema aqui é que você só tem roles quando o authentication mode = "Windows". Para este modo, cada usuário precisa de uma conta de usuário válida para o Windows no servidor. Não é uma boa solução.
Felizmente eu encontrei um artigo interessante na MSDN. Quando você autentica seu usuário no form Login.aspx, deve conseguir determinar a que roles usuário pertence:
if (author.IsAdministrator)
roles = new string[] {"Admin", "Member"};
else
roles = new string[] {"Member"};
//1 hour sliding expiry time
Cache.Add(author.UniqueId, roles, null, DateTime.MaxValue,
TimeSpan.FromHours(1), CacheItemPriority.BelowNormal, null);
Criei uma tabela de strings para armazenar os roles aos quais o usuário pertence. Estes ficam então armazenadas na coleção Application[] por motivos de desempenho, do contrário teríamos de fazer um acesso ao banco de dados cada vez que fosse necessário obter os roles do usuário atual.
Agora, uma vez que os forms de autenticação não têm o conceito de roles, esses roles serão incluídos no cookie do usuário. Assim, temos de determinar quais são estes roles cada vez que uma autenticação é executada. Para isso precisamos de ir para o arquivo Global.asax:
protected void Application_AuthenticateRequest(
Object sender, EventArgs e)
{
if (HttpContext.Current.User != null)
{
if (HttpContext.Current.User.Identity.AuthenticationType != "Forms")
throw new Exception("Only forms authentication is supported, not " +
HttpContext.Current.User.Identity.AuthenticationType);
System.Security.Principal.IIdentity userId =
HttpContext.Current.User.Identity;
//Do we have some roles to retrieve? If so, replace the user object
if (Application[userId.Name] != null)
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(
userId, (string[]) Cache[userId.Name]
);
}//user != null
}
Esta rotina verifica se o usuário atual ! = Null. Isto significa que a página está em um local protegido. Se este for o caso, então nós usamos o UserId como a chave para a coleção Cache[], para encontrar uma lista de roles. Se estas roles existem, então reatribuímos ao usuário atual um objeto que nós mesmos criamos, um objeto que tem uma lista de roles.
Conclusão
A segurança baseada em roles é muito útil em aplicações web. Com umas poucas linhas de código simples é possível implementar segurança baseada em roles para usuários que não têm um login válido para o Windows.