Filter para .css/.js?

Estou utilizando um Filter para restringir acesso a pasta /admin da minha aplicação JSF.

Lá existe a seguinte estrutura:

/admin/index.xhtml
/admin/menu.xhtml
/admin/img/logo.gif
/admin/css/estilo.css
/admin/js/functions.js

Na verdade gostaria de restringir apenas acesso aos arquivos .xhtml da pasta /admin, não queria gastar processamento fazendo o filtro em imagens e arquivos .css, já que é totalmente desnecessário.

existe essa possibilidade?
essa ‘checagem’ do Filtro em imagens dá uma diferença significante no processamento?

obs: não queria mover a pasta img/css/js para fora de /admin por questões de organização.

Danilo,

Eu tenho usado filtros para o controle de acesso com sucesso há muito tempo. Uma vez eu tive a curiosidade de verificar qual seria a “perda” com o uso desses filtros e aí eu coloquei o seguinte código no doFilter:

long ini = System.currentTimeMillis();

//o que desejo medir - tempo de processamento

long fim = System.currentTimeMillis();
long dif = fim - ini;
System.out.println("Tempo: " + dif + " em milissegundos.");

Foi surpreendente a relação custo X benefício. O filtro bem programado tem um custo muito baixo.

Quanto a sua questão: obtenha a URI (String URI = request.getRequestURI(); ) e verifique a String com endsWith. O ideal é criar uma lista com as extensões liberadas.

É possível também trabalhar com expressões regulares de forma a verificar padrões dentro da string, aumentando os recursos do filtro.

Espero ter sido útil.

É uma boa idéia, mas a minha intenção era que nem entrasse no Filter.
pelo jeito isso não é possível né?
pra evitar mexer no Filter, acho que vou dar um jeito de mover os diretórios pra fora de /admin mesmo.

Obrigado

[quote=danilowz]É uma boa idéia, mas a minha intenção era que nem entrasse no Filter.
pelo jeito isso não é possível né?
pra evitar mexer no Filter, acho que vou dar um jeito de mover os diretórios pra fora de /admin mesmo.

Obrigado[/quote]

Recomendo você mudar a estrutura de diretórios de forma que estes recursos fiquem fora do filtro.

/admin/
/css/
/js/

Caso não queira fazer isto você pode especificar o recurso especifico que você queira que entre no filtro.

 <filter-mapping>
  <filter-name>seuFiltro</filter-name>
  <url-pattern>/admin/index.xhtml</url-pattern>
  <url-pattern>/admin/menu.xhtml</url-pattern>
 </filter-mapping>

Pessoal,

Aproveitando o topico sobre filtros, gostaria de saber como posso fazer para restringir todas as minhas ações do Struts? É possível?
Eu fiz um filtro para restringir o acesso dos usuários, coloco os diretórios e os arquivos que não podem ser acessados sem login, porém eu tenho varias ações no meu sistema (varios .do) e não quero ficar listando todos dentro da url-pattern, tentei colocar /.do e não funcionou, se eu colocar / tambem nao va i, alguma ideia?

Jeff,

O filtro restringe todas as requisições se você colocar no web.xml o mapeamento /*, conforme o exemplo abaixo:

&lt;filter&gt;
        &lt;filter-name&gt;FiltroControleAcesso&lt;/filter-name&gt;
        &lt;filter-class&gt;br.com.acessos.FiltroControleAcesso&lt;/filter-class&gt;
        &lt;init-param&gt;
            &lt;description&gt;URLs a serem ignoradas pelo Controle de Acesso&lt;/description&gt;
            &lt;param-name&gt;enderecosLivres&lt;/param-name&gt;
            &lt;param-value&gt;/css;/img;/js&lt;/param-value&gt;
        &lt;/init-param&gt;
    &lt;/filter&gt;
    &lt;filter-mapping&gt;
        &lt;filter-name&gt;FiltroControleAcesso&lt;/filter-name&gt;
        &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
    &lt;/filter-mapping&gt;

O meu controle de acesso usa uma tabela em um banco de dados para verificar a cada requisição se o usuário pode acessar uma determinada URI. Os endereços livres são processados no filtro e caso coincida com a URI, nenhuma nova verificação é feita.

Por favor, explique melhor o que não funcionou para as URIs terminadas em DO, pois é perfeitamente viável o seu uso.

Armenio,

Eu vou rever meu web.xml aqui e tesar novamente, como é uma aplicação simples não vi a necessidade de criar uma tabela para dizer as permissões de cada usuário.
O que está acontecendo quando eu coloco /* é que a aplicação não roda, não sei se entra em loop, sei la, e quando colokei /*.do, eu tentei acessar uma ação e funcionou, mas como disse: vou rever aqui seguindo o teu exemplo, como estou fazendo mta coisa ao mesmo tempo, posso ter deixado algo passar sem perceber e me enganado.

Se eu colocasse no meu web.xml /*.do dentro do url-pattern, era para funcionar? Todas as minhas ações só seriam executadas se estivesse logado?

Uma dica Jeff,

O /* pega TUDO, ou seja, todas as requisições. Por isso não funcionou.

Você não precisa criar uma tabela agora enquanto estiver fazendo testes. Coloque no filtro um “if” para uma determinada URI terminada em DO de forma a redirecionar para uma página de erro. Por exemplo:

if (autorizado) {                         //autorizado
         chain.doFilter(request, response);
      } else if (!autorizado && usr != null) {  //não autorizado

         RequestDispatcher rd = hrequest.getRequestDispatcher("/login/nautor.jsp");
         rd.forward(request, response);
      } else {                                  //não logado
         session.setAttribute("URI", URI); //coloco isso para poder continuar se o usuário conseguir logar.
         RequestDispatcher rd = hrequest.getRequestDispatcher("/login/index.jsp");
         rd.forward(request, response);
      }

No lugar da minha flag “autorizado” teste se é uma determinada URI e redirecione para uma página de erro, ou então execute chain.doFilter para prosseguir normalmente.

Espero ter sido útil.

Entao o /* não irá funcionar mesmo?
Se eu coloco /* a aplicação é construida com sucesso, porém não abre nada no browser, parece q fica em loop.
Se eu colocar /*.do a aplicação nem roda nem eh construida, da erro na implementação do modulo.

O /* funciona sim, mas o código do filtro é que vai definir se o todo funciona ou não.

Quanto /*.do não funciona mesmo, pois o mapeamento precisa ter uma URI válida e URIs não têm extensão. Use somente nomes de pastas e o curinga *.

Como é o código do seu filtro?

O problema é que tenho varias ações, muitas mesmo, não quero ficar lsitando todas no meu web.xml nem verificando todas, queria alguma coisa mais automatica, mas enfim.

Meu filtro esta assim:

package catalogo.controle.seguranca;

import catalogo.modelo.Usuario;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class FiltroLogado implements Filter{

    public void init(FilterConfig filterConfig) throws ServletException {
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        
        HttpSession sessao = ((HttpServletRequest) request).getSession();

        Usuario usuario = (Usuario) sessao.getAttribute("usuario");

        if( usuario == null )
        {
            ((HttpServletResponse) response).sendRedirect("/Catalogo/");
        }        
        else
        {
            chain.doFilter(request, response);
        }
    }

    public void destroy() {
    }

}

Meu web.xml (por enkanto esta assim):

  <filter>
        <filter-name>Filtro Logado</filter-name>
        <filter-class>catalogo.controle.seguranca.FiltroLogado</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Filtro Logado</filter-name>
        <url-pattern>/home.jsp</url-pattern>
        <url-pattern>/acessoNegado.jsp</url-pattern>
        <url-pattern>/erroLogin.jsp</url-pattern>
        <url-pattern>/uteis/*</url-pattern>
        <url-pattern>/usuarios/*</url-pattern>
        <url-pattern>/configuracoes/*</url-pattern>
    </filter-mapping>

OK, Jeff, agora eu entendi.

O esquema é o seguinte: o mapeamento do filtro deve ser abrangente e o código do filtro é que deve ser detalhado.

O ideal é que o seu filtro acesse uma consulta que retorne as pastas que um determinado grupo de usuários têm direito a acessar. De posse dessa lista de pastas, você compara com a URI que o usuário está desejando acessar e aí libera ou não.

Os mapeamentos dos Actions do Struts devem ser compostos de "pastas" também, por exemplo: /alunos/manter.jsp executa um action /alunos/manter.do que inclui ou altera os dados do Aluno. A pasta a ser cadastrada no banco é /alunos.

Essa configuração que você usou no web.xml é ruim, pois é necessário listar uma série de mapeamentos.

O modelo de dados é relativamente simples: usuários —> grupos —> mapeamentos.

Espero ter sido útil.

Entendi, Armênio.

Então eu tenho que criar uma tabela com os acessos dos meus grupos de usuários?
Eu ja tinha pensado em colocar as ações do struts em pastas tambem, mas achei q não seria tao util, valeu pela ajuda.
Voce poderia me dar algum exemplo de como ficaria o meu web.xml mais abrangente como falou? Como ficaria minha tabela tambem?
No meu filtro eu vou ter que no doFilter acessar essa tabela passando o tipo de usuario(perfil), vou ter que criar um DAO para isso?

Ah soh um detalhe: a intenção desse meu filtro é apenas verificar se o usuario esta logado, por isso queria que fosse feito em todo os arquivos, inclusive ações do Struts, teria como fazer isso sem envovler BD? Ou seria melhor fazer um if em todos os jsps? Esse filtro apenas é para essa verificação, faço a verificação de autorização em outro filtro

Segue uma sugestão de filtro:

public void doFilter(ServletRequest request, ServletResponse response,
           FilterChain chain)
           throws IOException, ServletException {

      boolean autorizado = false;

      HttpServletRequest hrequest = (HttpServletRequest) request;

      //processa as URIs que estão na lista de exceções.
      String URI = hrequest.getRequestURI();
      String ctx = hrequest.getContextPath();
      for (int i = 0; i &lt; enderecosLivres.length; i++) {
         if (URI.startsWith(ctx + enderecosLivres[i] + &quot;/&quot;)
                 || URI.equals(ctx + &quot;/&quot;)
                 || URI.startsWith(ctx + &quot;/login&quot;)
                 || URI.contains(&quot;favicon.ico&quot;)) {
            autorizado = true;
            break;
         }
      }

      HttpSession session = hrequest.getSession(true);
      String usr = null;
      String pwd = null;
      if (!autorizado) { //não está na lista de exceções
         usr = (String) session.getAttribute(&quot;corporativo_usr&quot;);
         pwd = (String) session.getAttribute(&quot;corporativo_pwd&quot;);
         if (!Validador.vazio(usr)) {
            autorizado = controle.autorizar(usr, pwd, URI); //aqui está uma classe que faz a consulta ao banco.
         }
      }

      if (autorizado) {                         //autorizado
         chain.doFilter(request, response);
      } else if (!autorizado && usr != null) {  //não autorizado

         RequestDispatcher rd = hrequest.getRequestDispatcher(&quot;/login/nautor.jsp&quot;);
         rd.forward(request, response);
      } else {                                  //não logado
         session.setAttribute(&quot;msg&quot;, &quot;login&quot;);
         session.setAttribute(&quot;URI&quot;, URI);
         RequestDispatcher rd = hrequest.getRequestDispatcher(&quot;/login/index.jsp&quot;);
         rd.forward(request, response);
      }
   }

O fragmento do web.xml fica assim (adapte-o a sua realidade):

   &lt;filter&gt;
        &lt;filter-name&gt;FiltroControleAcesso&lt;/filter-name&gt;
        &lt;filter-class&gt;br.com.corporativo.acessos.FiltroControleAcesso&lt;/filter-class&gt;
        &lt;init-param&gt;
            &lt;description&gt;URLs a serem ignoradas pelo Controle de Acesso&lt;/description&gt;
            &lt;param-name&gt;enderecosLivres&lt;/param-name&gt;
            &lt;param-value&gt;/css;/img;/js;/principal;/index.jsp;/fckeditor;/userfiles&lt;/param-value&gt;
        &lt;/init-param&gt;
    &lt;/filter&gt;
    &lt;filter-mapping&gt;
        &lt;filter-name&gt;FiltroControleAcesso&lt;/filter-name&gt;
        &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
    &lt;/filter-mapping&gt;

Observe que o método da consulta retorna boolean, facilitando um pouco. Esse método é a chave de tudo, pois nele comparamos a URI desejada com os mapeamentos que o usuário tem acesso por intermédio do seu grupo. O ideal é criar um DAO para isolar o acesso ao banco de dados.

As tabelas são simples:
usuarios —> id de usuário, nome, senha etc
grupos_usuarios —> id do usuário, id do grupo.
grupos —> id do grupo, nome do grupo, etc.
mapeamentos —> id do mapeamento, id do grupo, URI do mapeamento.

Estou considerando que um usuário pode pertencer a vários grupos e um grupo tem vários mapeamentos. Um mapeamento poderia aparecer em vários grupos se você quiser, mas eu preferi um modelo mais simples.

Procure implementar aos poucos de forma a poder testar e dominar completamente o modelo.

Boa Sorte!

Armênio,

Muito obrigado pela ajuda.
Confesso que fiquei com algumas dúvidas e um pouco perdido, mas vou tentando aqui e aos poucos vou postando o que não conseguir resolver.
Só mais uma coisa: esse filtro que estou implementando agora ainda não é para verificar as permissões do usuário e sim verificar se o usuário está logado para poder acessar algum arquivo, acho que apenas para verificar se está logado não preciso envolver BD, ou estou errado? Como posso melhorar meu web.xml e meu filtro para apenas ser utilizado para a verificação da autenticação do usuario, ja que não esta legal o meu web.xml?

Jeff,

Implemente o filtro como eu passei comentando as linhas 28 e 29 que fazem acesso ao controle. Com isso você já fica sabendo se o usuário está logado ou não (através das variáveis de sessão). Não se esqueça de colocar essas variáveis na sessão no processo de login.

Fique tranquilo, pois o assunto não é tão trivial assim. Vamos seguindo passo-a-passo, entendendo cada etapa / conceito.

Conte comigo para matar as dúvidas.

Vou tentar aqui.
Qualquer duvida vou postando.
Qualquer coisa abro um novo topico.
Muito obrigado pela atenção e paciencia, quem dera se todos do forum fossem assim.
Obrigado mesmo.

Surgiu uma duvida aqui agora:
Como devo criar a variavel enderecosLivres?

Jeff,

Segue uma sugestão de código:

public class FiltroControleAcesso implements Filter {

   private FilterConfig filterConfig = null;
   private String[] enderecosLivres = null;
   private ControleAcesso controle = null;

   @Override
   public void init(FilterConfig filterConfig) {
      try {
         this.filterConfig = filterConfig;
         this.enderecosLivres = filterConfig.getInitParameter(&quot;enderecosLivres&quot;).split(&quot;;&quot;);
         InitialContext ictx = new InitialContext();
         controle = (ControleAcesso) ictx.lookup(&quot;corporativo/ControleAcessoBean&quot;);
      } catch (Exception ex) {
         ex.printStackTrace();
      }

   }

   @Override
   public void doFilter(ServletRequest request, ServletResponse response,
           FilterChain chain)
           throws IOException, ServletException {

      boolean autorizado = false;

      HttpServletRequest hrequest = (HttpServletRequest) request;

      //processa as URIs que estão na lista de exceções.
      String URI = hrequest.getRequestURI();
      String ctx = hrequest.getContextPath();
      for (int i = 0; i &lt; enderecosLivres.length; i++) {
         if (URI.startsWith(ctx + enderecosLivres[i] + &quot;/&quot;)
                 || URI.equals(ctx + &quot;/&quot;)
                 || URI.startsWith(ctx + &quot;/login&quot;)
                 || URI.contains(&quot;favicon.ico&quot;)) {
            autorizado = true;
            break;
         }
      }

      HttpSession session = hrequest.getSession(true);
      String usr = null;
      String pwd = null;
      if (!autorizado) { //não está na lista de exceções
         usr = (String) session.getAttribute(&quot;corporativo_usr&quot;);
         pwd = (String) session.getAttribute(&quot;corporativo_pwd&quot;);
         if (!Validador.vazio(usr)) {
            autorizado = controle.autorizar(usr, pwd, URI);
         }
      }

      if (autorizado) {                         //autorizado
         chain.doFilter(request, response);
      } else if (!autorizado && usr != null) {  //não autorizado

         RequestDispatcher rd = hrequest.getRequestDispatcher(&quot;/login/nautor.jsp&quot;);
         rd.forward(request, response);
      } else {                                  //não logado
         session.setAttribute(&quot;msg&quot;, &quot;login&quot;);
         session.setAttribute(&quot;URI&quot;, URI);
         RequestDispatcher rd = hrequest.getRequestDispatcher(&quot;/login/index.jsp&quot;);
         rd.forward(request, response);
      }
   }

   public FilterConfig getFilterConfig() {
      return (this.filterConfig);
   }

   public void setFilterConfig(FilterConfig filterConfig) {
      this.filterConfig = filterConfig;
   }

   @Override
   public String toString() {
      if (filterConfig == null) {
         return (&quot;FiltroControleAcesso()&quot;);
      }
      StringBuffer sb = new StringBuffer(&quot;FiltroControleAcesso(&quot;);
      sb.append(filterConfig);
      sb.append(&quot;)&quot;);
      return (sb.toString());
   }

   @Override
   public void destroy() {
   }
}

Ignore as linhas 12, 13, 48, 49, 50 que se referem ao controle de acesso propriamente dito.

Espero ter sido útil.

Peguei o teu código e alterei com as minhas necessidades e alterei tambem o meu web.xml, mas não esta funcionando, se eu tento acessar algum arquivo que não esta na miha lista de permissoes(web.xml) nao sou redirecionado para a pagina de login.

web.xml

<filter> <filter-name>FiltroControleAcesso</filter-name> <filter-class>catalogo.controle.seguranca.FiltroControleAcesso</filter-class> <init-param> <description>URLs a serem ignoradas pelo Controle de Acesso</description> <param-name>enderecosLivres</param-name> <param-value>/css;/imagens/;/uteis;/login.jsp</param-value> </init-param> </filter> <filter-mapping> <filter-name>FiltroControleAcesso</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

Filtro:

[code]package catalogo.controle.seguranca;

import catalogo.modelo.Usuario;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

public class FiltroControleAcesso implements Filter {

private FilterConfig filterConfig = null;
private String[] enderecosLivres = null;
//private ControleAcesso controle = null;

@Override
public void init(FilterConfig filterConfig) {

   try
   {
       this.filterConfig = filterConfig;
       this.enderecosLivres = filterConfig.getInitParameter("enderecosLivres").split(";");
       //InitialContext ictx = new InitialContext();
       //controle = (ControleAcesso) ictx.lookup("corporativo/ControleAcessoBean");
   }
   catch (Exception ex)
   {
       ex.printStackTrace();
   }

}

@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
boolean autorizado = false;
HttpServletRequest hrequest = (HttpServletRequest) request;

   //processa as URIs que estão na lista de exceções.
   String URI = hrequest.getRequestURI();
   String ctx = hrequest.getContextPath();

   for (int i = 0; i < enderecosLivres.length; i++)
   {
       if (URI.startsWith(ctx + enderecosLivres[i] + "/")
           || URI.equals(ctx + "/")
           || URI.startsWith(ctx + "/")) 
       {
           autorizado = true;
           break;
       }
   }

   HttpSession session = hrequest.getSession(true);
   Usuario user = null;
   //String pwd = null;
   
   if (!autorizado) //não está na lista de exceções
   {
       user = (Usuario) session.getAttribute("usuario");
       //pwd = (String) session.getAttribute("corporativo_pwd");

     /*if (!Validador.vazio(usr)) {
        autorizado = controle.autorizar(usr, pwd, URI);
     }*/
   }
   
   if (autorizado) //autorizado
   {
       chain.doFilter(request, response);
   }
   else if (!autorizado && user != null) //não autorizado
   {
       RequestDispatcher rd = hrequest.getRequestDispatcher("/acessoNEgado.do");
       rd.forward(request, response);
   }
   else //não logado
   {
       session.setAttribute("msg", "login");
       session.setAttribute("URI", URI);
       RequestDispatcher rd = hrequest.getRequestDispatcher("/logar.do");
       rd.forward(request, response);
   }

}

public FilterConfig getFilterConfig() {
return (this.filterConfig);
}

public void setFilterConfig(FilterConfig filterConfig) {
this.filterConfig = filterConfig;
}

@Override
public String toString() {

   if (filterConfig == null) {
       return ("FiltroControleAcesso()");
   }

   StringBuffer sb = new StringBuffer("FiltroControleAcesso(");
   sb.append(filterConfig);
   sb.append(")");
   return (sb.toString());

}

@Override
public void destroy() {
}
}
[/code]

Fiquei com algumas dúvidas no for dentro do doFilter, que percorre a lsita de endereços livres, acho que posso ter errado ali