Archive

Archive for 02/05/2017

Criando sua Própria Tag Library do Shiro

Se você precisa de mais granularidade na checagem de permissões em uma página web, como por exemplo determinar se um botão deve ou não ser exibido, o Shiro oferece uma API que te permite fazer sua implementação nos métodos do seu controller/managed bean – não faça scriplets! No exemplo do botão, você poderia condicionar sua exibição assim:

<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:p="http://primefaces.org/ui">
   <body>
      <p:commandLink action="#{appMB.executar()}" 
          rendered="#{appMB.podeExecutar()}">Executar</p:commandLink>
   </body>
</html>

A implementação do método podeExecutar() utiliza a API do Shiro para verificar se o usuário tem determinada permissão:

public boolean podeExecutar() throws IOException {
   Subject subject = SecurityUtils.getSubject();
   return subject.isPermitted("PERMISSAO_EXECUCAO");
}

O problema é que você tende a reescrever esse mesmo código ou um muito parecido em cada managed bean que precisar de autorização. Felizmente, o Shiro possui uma tag library útil para quem trabalha com arquivos JSP, mas se você trabalha com JSF, não há nada pronto para utilizar. Porém, é possível criar sua própria biblioteca reutilizável à partir daquele código de checagem que você inseriu no managed bean. Vamos definir a assinatura de uma tag chamada “hasPermissao” que receba como parâmetro uma permissao:

<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib 
   version="2.2"
   xmlns="http://xmlns.jcp.org/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
   http://xmlns.jcp.org/xml/ns/javaee/web-facelettaglibrary_2_2.xsd">
   <namespace>http://app.com.br/security</namespace>
   <tag>
      <description><![CDATA[Verifica a permissao do usuario]]></description>
      <tag-name>hasPermissao</tag-name>
      <component>
         <component-type>permitido</component-type>
      </component>
      <attribute>
         <description><![CDATA[Permissao a ser verificada.]]></description>
         <name>permissao</name>
         <required>true</required>
         <type>java.lang.String</type>
      </attribute>
   </tag>
</facelet-taglib>

Uma vez criada a biblioteca, ela deve ser cadastrada no web.xml:

<context-param>
   <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
   <param-value>/WEB-INF/app.taglib.xml</param-value>
</context-param>

Em seguida, vamos criar uma classe que extende UIComponentBase e é anotada como @FacesComponent. Essa implementação “esconde” todos os componentes visuais delimitados pela tag caso o usuário não esteja autorizado:

@FacesComponent(createTag = true, 
   namespace = "http://app.com.br/security", 
   tagName = "hasPermissao", 
   value = "hasPermissao")
public class PermissaoTag extends UIComponentBase {

   @Override
   public String getFamily() {
      return "app";
   }

   @Override
   public void encodeBegin(FacesContext context)
      throws IOException {
      String permissao = (String)getAttributes().get("permissao");
      Subject subject = SecurityUtils.getSubject();
      if (!subject.isPermitted(permissao)) {
         getChildren().stream().forEach(
            s -> s.setRendered(false));
      }
   }
}

Por último, importe a tag em seu arquivo xhtml e utilize no trecho de código sujeito à autorização:

<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:p="http://primefaces.org/ui"
   xmlns:app="http://app.com.br/security">
   <body>
     <app:hasPermissao permissao="PERMISSAO_EXECUCAO">
       <p:commandLink action="#{appMB.executar()}">Executar</p:commandLink>
     </app:hasPermissao>
   </body>
</html>

Referências

1. [https://www.mkyong.com/jsf2/custom-tags-in-jsf-2-0/]
2. [https://shiro.apache.org/web.html#Web-taglibrary]
3. [https://shiro.apache.org/java-authorization-guide.html#programmatic-authorization]