O Forms Authentication é o mecanismo que temos desde a primeira versão do ASP.NET, e que hoje faz parte do seu core, e é responsável pelo gerenciamento do processo de autenticação de um usuário, utilizando cookies. É importante dizer que este recurso apenas se encarrega de gerenciar o cookie que é criado, se certificando de que ele existe, é válido e não está expirado, atuando como um “guarda” logo nos primeiros estágios da requisição.
Só que a verificação quanto a existência daquele usuário é importante, e temos algumas opções para isso. Uma delas é recorrer à um banco de dados customizado, um arquivo Xml, ou ainda, utilizar toda a infraestrutura que o ASP.NET fornece a partir da versão 2.0, conhecida como Membership. Além dessas alternativas, para alguns cenários extremamente simplistas, podemos utilizar o próprio arquivo Web.config para armazenar os usuários. Para isso, utilizamos o sub-elemento credentials do elemento forms, que é utilizado para configurar o Forms Authentication. Abaixo temos este exemplo:
<?xml version=”1.0″?>
<configuration>
<system.web>
<authentication mode=”Forms”>
<forms loginUrl=”~/PaginaDeLogin.aspx”>
<credentials passwordFormat=”Clear”>
<user name=”Israel” password=”123″/>
<user name=”Claudia” password=”456″/>
</credentials>
</forms>
</authentication>
</system.web>
</configuration>
Com os usuários ali catalogados, para que seja possível verificar a existência do mesmo, recorremos ao método estático Authenticate da classe FormsAuthentication. Este método receberá duas strings, que correspondem ao login e senha, retornando um valor boleano indicando se o usuário existe ou não dentro do arquivo de configuração. Isso é o suficiente para manter os usuários da aplicação, sem necessitar de algum recurso extra para armazenar os usuários. Abaixo o código que faz essa checagem:
if (FormsAuthentication.Authenticate(this.Login.Text, this.Senha.Text))
FormsAuthentication.RedirectFromLoginPage(this.Login.Text, false);
Apesar da Microsoft suportar um modelo de gerenciamento de usuários de forma simples, ela não disponibiliza um recurso nesta mesma linha para armazenar os papéis do usuário. Talvez isso se deva ao fato de isso já deve ser encarado como sendo algo mais rebuscado, ou seja, devendo recorrer à algo mais elegante para o gerenciamento de usuários e seus respectivos papéis. Mas para aqueles que ainda desejam manter a simplicidade, você pode ter isso com um pouco de trabalho. O primeiro passo consiste na criação de um arquivo para armazenar os papéis, e para isso vamos utilizar o formato Xml, relacionando os papéis através do nome do usuário. Abaixo temos o conteúdo do arquivo que chamei de userRoles.config, mas que não possui nenhuma relação com o arquivo de configuração da aplicação, o Web.config.
<?xml version=”1.0″?>
<userRoles>
<user name=”Israel”>
<roles>
<role name=”Admin” />
<role name=”TI” />
</roles>
</user>
<user name=”Claudia”>
<roles>
<role name=”Gerencia” />
</roles>
</user>
</userRoles>
Com todos papéis ali definidos, precisamos criar uma classe que será responsável pela busca e extração dos papéis de um determinado usuário. Essa classe estática, chamada de ConfigurationRoles, é extremamente simples, que expõe um método chamado GetRolesByUser, e que recebe o nome do usuário, e efetua a busca no arquivo userRoles.config utilizando LINQ To Xml, e caso encontre-o, retornará um array de strings, onde cada elemento corresponde à um papel em que o usuário está contido. Abaixo temos a classe que acabou de ser descrita:
internal static class ConfigurationRoles
{
private static readonly string RolesFilePath;
static ConfigurationRoles()
{
RolesFilePath = HttpContext.Current.Server.MapPath(“~/userRoles.config”);
}
internal static string[] GetRolesByUser(string username)
{
XDocument doc = XDocument.Load(RolesFilePath);
return
(
from u in doc.Descendants(“user”)
where u.Attribute(“name”).Value == username
from r in u.Descendants(“role”)
select r.Attribute(“name”).Value
).ToArray();
}
}
Só que ainda nos resta utilizar isso na aplicação. Para interceptar o processo de autenticação, podemos utilizar o evento Authenticate da classe FormsAuthenticationModule, que é o responsável por gerenciar o processo da autenticação através do Forms Authentication. Esse evento nos permitirá a customização do objeto que representa o usuário (IIdentity) e seus papéis (IPrincipal), que é exatamente o que precisamos fazer. Para tratarmos o evento, criamos no arquivo Global.asax um método nomeado como FormsAuthentication_OnAuthenticate, que automaticamente o ASP.NET o invocará quando o evento Authenticate acontecer. Abaixo temos a o código referente a este processo:
public class Global : HttpApplication
{
public void FormsAuthentication_OnAuthenticate(object sender, FormsAuthenticationEventArgs e)
{
if (FormsAuthentication.CookiesSupported)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
FormsAuthenticationTicket ticket =
FormsAuthentication.Decrypt(
Request.Cookies[FormsAuthentication.FormsCookieName].Value);
string username = ticket.Name;
e.User =
new GenericPrincipal(
new GenericIdentity(username),
ConfigurationRoles.GetRolesByUser(username));
}
}
else
{
throw new HttpException(“Modelo de autenticação não suportado.”);
}
}
}
Note que se houver um cookie de autenticação criado, decriptamos o mesmo extraindo o nome do usuário. Em seguida, construímos uma nova identidade a partir daquele nome de usuário, e recorremos a classe que criamos acima, extraindo todos os papéis daquele usuário, envolvendo tudo isso em um objeto chamado GenericPrincipal. Note que a instância é atribuída à propriedade User do parâmetro FormsAuthenticationEventArgs que é passado ao método, e que a partir de agora, será utilizado por toda aplicação.
Apesar de tudo isso funcionar, ele deve ser utilizado em casos realmente simples, onde a demanda por gerenciar usuários e papéis em tempo de execução não seja necessária. Do contrário, o melhor é recorrer à alguns recursos que já temos à disposição tanto para o gerenciamento de usuários como o de papéis.