quarta-feira, 24 de fevereiro de 2016

Autenticação e Autorização no JSF com Realm

    O "Realm" é um "banco de dados" de nomes de usuários e senhas que identificam usuários válidos de uma aplicação web (ou conjunto de aplicações web), além de uma enumeração da lista de funções associadas a cada usuário válido. 
    É necessário algumas configurações para fazer a autenticação e controlar o acesso dos usuários. A autenticação é definida por papeis, e não usuário por usuário, uma vez que as configurações são feitas em arquivos XML.
  O JBoss e o TomCat permitem essa configuração. Eles definem uma interface Java (org.apache.catalina.Realm) que podem ser implementadas por componentes "plug-in"  para estabelecer esta conexão. Cinco plug-ins padrão são fornecidos, suportando ligações a várias fontes de informação de autenticação:
  • JDBCRealm - Acessa informações de autenticação armazenadas em um banco de dados relacional, acessado através de um driver JDBC.
  • DataSourceRealm - Acessa informações de autenticação armazenadas em um banco de dados relacional, acessado através de uma chamada DataSource JNDI JDBC.
  • JNDIRealm - Acessa informações de autenticação armazenadas em um servidor de diretório LDAP com base, acessado através de um provedor de JNDI.
  • MemoryRealm - Acessa informações de autenticação armazenadas em um objeto de coleção in-memory, que é inicializada a partir de um documento XML (conf / tomcat-users.xml).
  • JAASRealm - Acessa informações de autenticação através do framework Java Autenticação e Autorização de Serviço (JAAS).
    Vou mostrar a implementação de um JDBCRealm.

    Primeiro deve-se ter duas tabelas, uma com login e senha, e outra com login e o papel do usuário (vendedor, gerente financeiro, secretario, diretor, etc). Essas tabelas podem ter mais campos caso seja uma necessidade do seu modelo de dados.

create table users (
  login         varchar(15) not null primary key,
  senha         varchar(15) not null
);

create table user_roles (
  login         varchar(15) not null,
  funcao        varchar(15) not null,
  primary key (login, funcao)
);

    Dentro do diretório META-INF que fica dentro de WebContent, cria-se um arquivo XML chamado context.xml.

    Dentro desse arquivo é preciso preencher dados referentes a classe que implementa o plugin realm que vamos usar, dados referentes a conexão com o banco de dados e também os dados referentes as tabelas e colunas que irão conter os dados de usuários e acessos. Veja o exemplo que segue:

<?xml version="1.0" encoding="UTF-8"?>
<Context>
      <Realm className="org.apache.catalina.realm.JDBCRealm" driverName="org.postgresql.Driver" connectionURL="jdbc:postgresql://localhost:5433/seguranca" connectionName="usuario do banco" connectionPassword="senha do banco" userTable="nome da tabela de usuario" userNameCol="nome da coluna de usuario" userCredCol="nome da coluna de senha" userRoleTable="nome da tabela de permissões" roleNameCol="nome da coluna que contem a permissao"/>
<!-- é importante colocar o driver do banco de dados na biblioteca do servidor (mesmo quando já existe na aplicação) -->

</Context>

    Para usar senhas criptografadas com MD5, basta acrescentar um parâmetro chamado "digest" e passar o MD5. (digest="MD5") .

    O arquivo Web.xml deve ser configurado com as regras de acesso. Segue o exemplo abaixo:

  <!-- configurações de acesso e autenticação -->
  
  <!-- Essa parte é obrigatória, onde se informa o tipo de autenticação e as páginas de login e erro -->

  <login-config>
  <auth-method>FORM</auth-method>
  <form-login-config>
  <form-login-page>/Login.xhtml</form-login-page>
  <form-error-page>/Login.xhtml</form-error-page>
  </form-login-config>
  </login-config>
  
  <!-- Aqui eu informo cada papel que vai ter no meu sistema -->

  <security-role>
  <role-name>vendedor</role-name>
  </security-role>
  <security-role>
  <role-name>gerente</role-name>
  </security-role>
  <security-role>
  <role-name>caixa</role-name>
  </security-role>
  
  <!-- Nessa parte informamos as páginas que cada papel pode ter acesso. 
  A TAG <web-resource-name> serve apenas para dar um titulo ao grupo de acessos-->
  
<security-constraint>
  <web-resource-collection>
  <web-resource-name>Perfil Vendedor</web-resource-name>
 
  <url-pattern>/CadastrarCliente.xhtml</url-pattern>
  <url-pattern>/ConsultarCliente.xhtml</url-pattern>
  <url-pattern>/EditarCliente.xhtml</url-pattern>
  <url-pattern>/CadastrarVenda.xhtml</url-pattern>
  <url-pattern>/ConsultarVenda.xhtml</url-pattern>
  </web-resource-collection>
  <auth-constraint>
  <role-name>vendedor</role-name>
  </auth-constraint>
  </security-constraint>
  
  <security-constraint>
  <web-resource-collection>
  <web-resource-name>Perfil Gerente</web-resource-name>
 
  <url-pattern>/CadastrarCliente.xhtml</url-pattern>
  <url-pattern>/ConsultarCliente.xhtml</url-pattern>
  <url-pattern>/EditarCliente.xhtml</url-pattern>
  <url-pattern>/CadastrarFuncionario.xhtml</url-pattern>
  <url-pattern>/ConsultarFuncionario.xhtml</url-pattern>
  <url-pattern>/EditarFuncionario.xhtml</url-pattern>
  <url-pattern>/CadastrarVenda.xhtml</url-pattern>
  <url-pattern>/ConsultarVenda.xhtml</url-pattern>
  <url-pattern>/EditarVenda.xhtml</url-pattern>
  </web-resource-collection>
  <auth-constraint>
  <role-name>gerente</role-name>
  </auth-constraint>
  </security-constraint>
  
  <security-constraint>
  <web-resource-collection>
  <web-resource-name>Perfil Caixa</web-resource-name>
 
  <url-pattern>/CadastrarCliente.xhtml</url-pattern>
  <url-pattern>/ConsultarCliente.xhtml</url-pattern>
  <url-pattern>/EditarCliente.xhtml</url-pattern>
  <url-pattern>/CadastrarVenda.xhtml</url-pattern>
  <url-pattern>/ConsultarVenda.xhtml</url-pattern>
  <url-pattern>/EditarVenda.xhtml</url-pattern>
  </web-resource-collection>
  <auth-constraint>
  <role-name>caixa</role-name>
  </auth-constraint>
  </security-constraint>
  <!-- fim das configurações de acesso e autenticação -->    

    Pronto, as configurações estão feitas e prontas para uso. O passo final é criar a página de login (Login.xhtml) e o ManagedBean que vai receber o usuário e senha.
No managedBean, o método que vai ser executado na action do commandButton da página de login deve capturar a request e setar o usuário e senha como mostrado abaixo:

FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest(); request.login(login, senha);

E para fazer o logoff basta chamar:

FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest(); request.logoff();

E uma dica legal, é que como nos arquivos ".xhtml" podemos acessar a request, temos como renderizar botões e linkes apenas para usuários que terão acessos as páginas que eles redirecionam. Exemplo:

<h:button value="Editar Funcionario" outcome="EditarFuncionario" rendered="#{request.isUserInRole("gerente")}" />

O site do Jboss tem outras informações sobre como implementar um Realm: https://docs.jboss.org/jbossweb/3.0.x/realm-howto.html


Nenhum comentário:

Postar um comentário