As Roles ou papéis em português nos ajudam a gerenciar as autorizações que um determinado usuário tem dentro de uma aplicação. Essas roles nos permitem customizar o acesso a recursos da aplicação ou até mesmo da página. Imaginem a seguinte situação: você tem em sua intranet uma aplicação onde os usuários se autenticam e têm acesso à aplicação ASP.NET. Dentro desta aplicação existe uma página ASPX que lista os registros de uma determinada tabela da base de dados, mas somente quem é “Administrador” pode excluir informações desta tabela. Mas podemos ir além disso, ou seja, podemos até mesmo especificar que usuários não contidos na role “Administrador” não consigam abrir a página ExtratoPagamentos.aspx.
Com o uso de roles você consegue definir regras para isso, ou seja, você pode criar suas próprias regras durante o desenvolvimento, onde você pode dizer que somente usuários que estão contidos na role “Administrador” podem clicar no botão de exclusão do registro. Obviamente que somente depois de devidamente autenticado o usuário tem acesso a aplicação, já que roles não trabalham com usuários anônimos. Cada usuário pode estar contido em uma ou muitas roles, dando assim uma maior flexibilidade.
A organização de roles na aplicação ajuda bastante a definir a arquitetura da segurança da mesma, mas há também um diagrama na UML, chamado de Use Cases, onde é possível extrairmos possível usuários e roles que a aplicação poderá vir a ter. Como já notamos a importância disso, a Microsoft implementou (assim como o Membership) o modelo de Provider Model em sua arquitetura e, com isso, nos disponibilizou o que chamamos de Role Management API. Esta API não está restrita a trabalharmos com páginas ou diretórios, mas a mesma fornece uma série de métodos para que, programaticamente, consigamos ajustar alguns recursos a roles específicas.
Para aqueles que já estão familiarizados com a arquitetura do Windows, verão uma grande semelhança entre as roles e os grupos de usuários do Windows. Já que utilizamos a arquitetura de Provider Models, a API pode ser tanto utilizada com a classe SqlRoleProvider quanto para a classe WindowsTokenRoleProvider. A primeira delas usa o SQL Server para o armazenamento das roles dos usuários. Já a segunda utiliza os grupos do Windows para trabalhar, mas lembrando que só é interessante o seu uso se for em uma intranet, pois o uso dela em uma aplicação que será vista por toda a internet é completamente inviável. Já para internet, devemos utilizar o FormsAuthentication para estarmos gerenciando os usuários dentro da aplicação e a API de Roles está completamente integrada com isso. Assim como no Membership, utilizaremos aqui a classe SqlRoleProvider (que usa um banco de dados dentro do SQL Server) para os exemplos de uso e configurações.
A configuração no arquivo Web.Config
A forma de configuração do Role Provider é bem parecida com a do Membership, pois temos que especificar todas as configurações que desejarmos para a API no arquivo Web.Config através do elemento roleManager. Este elemento também possui um elemento filho chamado providers, o qual recebe uma coleção dos providers que podem ser utilizados pela aplicação. Através da tabela abaixo analisaremos atributo por atributo destas configurações e para o que cada um deles serve:
|
|
Agora que já conhecemos todos os parâmetros possíveis dos elementos acima, veremos abaixo um exemplo de como estar configurando isso dentro do arquivo Web.Config da aplicação ASP.NET:
<?xml version="1.0"?> <configuration> <connectionStrings> <clear/> <add name="SqlConnectionString" connectionString="Data Source=local;Initial Catalog=DBTest;Integrated Security=True;"/> </connectionStrings> <system.web> <roleManager defaultProvider="SqlRoleProvider" enabled="true" cacheRolesInCookie="true" cookieName=".ASPROLES" cookieTimeout="30" cookiePath="/" cookieRequireSSL="false" cookieSlidingExpiration="true" cookieProtection="All" > <providers> <add name="SqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="SqlConnectionString" applicationName="NomeAplicacao" /> </providers> </roleManager> </system.web> </configuration> |
A classe Roles
A classe estática Roles, encontrada dentro do Namespace System.Web.Security, é usada pelo ASP.NET para criar e gerenciar as roles. Esta classe faz uso da classe FormsAuthentication (já existente nas versões anteriores do ASP.NET) para criar e gerenciar a autorização do usuário dentro da aplicação Web.
Falando um pouco sobre o seu funcionamento: existe um membro interno chamado s_Provider do tipo RoleProvider (a classe base para as classes concretas de RoleProvider, como por exemplo o SqlRoleProvider), o qual receberá a instância da classe concreta. Essa inicialização acontece quando um método interno chamado Initialize é executado. Ele se encarrega de extrair os providers do arquivo Web.Config e instancia-los para que, quando chamarmos os métodos e propriedades, já sejam efetivamente os métodos e propriedades da classe concreta que queremos utilizar. Indo um pouco mais abaixo, existe uma classe (também dentro do Namespace System.Web.Security) chamada RolePrincipal. Essa classe implementa a interface IPrincipal e representa o contexto de segurança da requisição HTTP corrente. Quando as roles estão habilitadas na aplicação, o módulo RoleManagerModule define a propriedade User da classe HttpContext da requisição corrente, com uma instância da classe RolePrincipal.
A classe RolePrincipal expõe as identidades de segurança da requisição HTTP e se encarrega de executar as checagens de roles. Se a propriedade CacheRolesInCookie estiver definida como True, a RolePrincipal tenta recuperar as roles que estão armazenadas em um cookie. Já, se esta opção estiver definida como False, a classe RolePrincipal recupera as roles do usuário através do provider especificado no arquivo Web.Config.
Como esta classe encapsula o acesso ao provider específico, ela fornece facilidades como: criação de novas roles, verificação de usuários, gerenciamento de roles em seu repositório (SQL Server, Grupos do Windows, etc). Como já vimos anteriormente o funcionamento interno desta classe, podemos perceber que o ASP.NET confia no provider especificado no Web.Config para se comunicar com a fonte de dados. Como já sabemos, o .NET Framework inclui a classe SqlRoleProvider para acesso e persistência dos dados no SQL Server e é este que vamos utilizar no decorrer dos exemplos deste artigo.
Mas esta arquitetura é extensível, ou seja, a qualquer momento eu posso criar o meu próprio provider de Roles, onde eu queira customizá-lo para um outro repositório qualquer. E, para que isso seja possível, é necessário herdarmos da classe abstrata chamada RoleProvider e customizá-la de acordo com o nosso repositório. Para ilustar o cenário, imaginemos que desejamos ter um provider de RoleProvider sendo persistido em um arquivo XML:
public class XmlRoleProvider : RoleProvider { // customizo aqui todos os métodos e // propriedades necessárias } |
Não vou me preocupar aqui em mostrar e explicar as propriedades da classe Roles justamente porque são propriedades de somente leitura e apenas devolvem os valores que configuramos no Web.Config para o provider. Nos concentraremos apenas nos métodos, pois é o mais importante, os quais nos dão todas as funcionalidades de manutenção e criação de roles na base de dados.
|
Depois da teoria, veremos abaixo um trecho curto de código que mostra como chamar esses métodos e propriedades via código:
// Criando Role if(!Roles.RoleExists("Administradores")) { Roles.CreateRole("Administradores"); } // Definindo Usuário para uma Role if(!Roles.IsUserInRole("IsraelAece", "Administradores")) { Roles.AddUserToRole("IsraelAece", "Administradores"); } // Recuperando Roles de um Usuário string[] roles = Roles.GetRolesForUser("IsraelAece"); foreach(string role in roles) { Response.Write(string.Format("Role: {0}<br>", role)); } // Excluindo Usuário da Role if(Roles.Delete("Administradores", false)) { Response.Write("Role excluída com sucesso."); } // Habilitando Recursos this.btnLiberarCredito.Visible = Roles.IsUserInRole("Administradores"); |
Além disso, ainda temos alguns outros lugares (não menos importantes) para utilizarmos as roles; um deles é no arquivo Web.Config. É nele que definimos páginas ou diretórios da aplicação que são restritas à determinadas roles. Vale lembrar que também é permitido termos vários arquivos Web.Config’s nas pastas internas onde, para cada uma, implementamos um arquivo de configuração definindo as roles, podendo sobrescrever as roles especificadas no arquivo Web.Config da raiz.
Para exemplificar o uso das roles no arquivo Web.Config, analise o código abaixo:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <location path="ExtratoConta.aspx"> <system.web> <authorization> <deny users="?" /> <allow roles="*" /> </authorization> </system.web> </location> <location path="DarCredito.aspx"> <system.web> <authorization> <deny users="?" /> <allow roles="Gerentes, Administradores" /> </authorization> </system.web> </location> </configuration> |
Nas especificações acima a página ExtratoConta.aspx está proibida para usuários anônimos (não autenticados) e permitida para todos os usuários autenticados (independentemente da role). Já a página DarCredito.aspx está proibida para usuários anônimos e permitida somente para usuários que estão contidos dentro da role “Gerentes” ou “Administradores”.
Mas o uso ainda não pára por aí. O ASP.NET 2.0 fornece um arquivo chamado Web.sitemap. Este arquivo, que em sua estrutura é um XML, tem a finalidade de carregar controles hierárquicos, como por exemplo: Menu, TreeView, SiteMapPath (controles contidos na Tab Navigation) da ToolBox do Visual Studio .NET 2005. Este arquivo é responsável por toda a navegação da aplicação e no elemento siteMapNode existe um atributo chamado roles, onde passamos as roles em que o usuário autenticado deve estar contido. Se não estiver, o item não chega à ser exibido para o usuário. Abaixo é mostrado um exemplo de um arquivo Web.sitemap com estas configurações:
<?xml version="1.0" encoding="utf-8" ?> <siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0"> <siteMapNode url="Default.aspx" title="Home"> <siteMapNode url="" title="ContaCorrente" title="Conta Corrente"> <siteMapNode url="ExtratoConta.aspx" title="Extrato" /> <siteMapNode url="DarCredito.aspx" title="Crédito" roles="Gerentes, Administradores" /> </siteMapNode> </siteMapNode> </siteMap> |
Boas Flavio,
É que estou utilizando segurança integrado ao Windows.
Para maiores informações sobre connectionstrings, você pode acessar este site: http://www.connectionstrings.com/
Olá Israel,
Gostaria de te colocar uma questão relacionada com isto da segurança. Tenho um conjunto de Providers próprios que desenvolvi ontem tenho tudo a validar direitinho, e tenho também umas classes extendidas do objecto IPrincipal e nela tenho apenas um objecto "private SecurityIdentity currentIdentity" – que extende a classe IIdentity.
O que me está a acontecer é que tenho um menu onde vou buscar as opções a um sitemap (configurado com securityTrimming=true e especificação das roles) e ao aefectuar debug, constato que ele me está a passar pelo método "public bool IsInRole(string role)" que tenho especificado mas não implementado no meu objecto extendido SecurityPrincipal. Está validação não deveria ser feita usando os providers? pq é que ele me vai a este objecto verificar se o user pertence à Role ou não? Não sei se é um comportamento normal..
Agradeço a tua ajuda.
Manuel
Boas Manuel,
Quando você utiliza a configuração padrão, o ASP.NET cria e utiliza a instância da classe RolePrincipal, que é responsável por fazer as checagens de autorização, através do método IsInRole(string role).
Se você notar, essa classe delega essa verificação para o provider de Roles que está atualmente configurado no arquivo Web.config.
Se você está criando a sua própria "principal" (através da interface IPrincipal), então você terá que fazer ou mesmo, ou seja, no método IsInRole, buscar a role no provider atualmente selecionado.
Olá Israel!
Gostaria se possível, mais detalhes do elemento "ConnectionStrings".
No seu exemplo não é especificado a senha de acesso ao SQL server…
Como aqui utilizo o usuário "sa", não estou conseguindo utilizar as roles contidas no banco (após rodar o aplicativo aspnet_regsql).