Como criar perfis de acesso usando Filtros - JSF

12 respostas
A

Galera,

É o seguinte: preciso criar permissão de acesso. Exemplo: usuario tipo Administrador acessa X páginas, usuário tipo Manager acessa Y páginas.
Logo, estudando e lendo um pouco, eu apliquei o conceito de filtros no meu web.xml para garantir uma autenticação segura. E sei também que de alguma forma (e é o que desejo compreender), que utilizando estes filtros eu consigo fazer a permissão de acesso. Logo, como descrito no meu web.xml abaixo, eu fiz três filtros (três perfis: admin, manager e user). Porém quando eu logo como manager por exemplo, a autenticação é realizada e é redirecionada para a página desejada. Porém, o conteúdo dela não é exibido e sim, está sendo requisitado o login novamente. No meu entendimento, quando mapeamos no filtro manager a tag /pages/* significa que todas as paginas contidas no diretorio pages serão permitidas. Mas não é o que ocorre, fazendo com que a autenticação seja solicitada sempre e nunca a página esperada é exibida, pq é redirecionada para a página de login. No filtro de administrador por exemplo, possuo um outro problema, onde o administrador deveria ter acesso a tudo, e ele não consegue tb acessar o que está dentro dos diretorios ‘pages’ e ‘user’. Estou fazendo a permissão de acesso corretamente? Como fazer com que o filtro seja respeitado de acordo com o perfil do usuário?

Obrigado pela atenção e tenham um ótimo dia!

Web.xml

<filter>
        <filter-name>AuthManager</filter-name>
        <filter-class>resources.AuthManager</filter-class>
    </filter>  
    <!-- Entity Manager Filter declaration -->
    <filter>
        <filter-name>AuthUser</filter-name>
        <filter-class>resources.AuthUser</filter-class>
    </filter>
    <filter>
        <filter-name>AuthAdmin</filter-name>
        <filter-class>resources.AuthAdmin</filter-class>
    </filter>
    <!-- Entity Manager Filter declaration -->
    <filter-mapping>
        <filter-name>AuthManager</filter-name>
        <url-pattern>/pages/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>AuthUser</filter-name>
        <url-pattern>/user/*</url-pattern>
    </filter-mapping>
    <!-- Filter is setup on all requests -->
    <filter-mapping>
        <filter-name>AuthAdmin</filter-name>
       <url-pattern>/admin/*</url-pattern>
    </filter-mapping>

AuthAdmin.java

public class AuthAdmin implements Filter {

    /** Logger */
    protected Logger log = Logger.getLogger(AuthAdmin.class.getName());
    private EntityManagerFactory entityManagerFactory;

    /**
     * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
     * @param config
     * @throws javax.servlet.ServletException
     */
    public void init(FilterConfig config) throws ServletException {
    }

    /** (non-Javadoc)
     * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
     * @param request
     * @param response
     * @param chain
     * @throws javax.servlet.ServletException
     * @throws java.io.IOException
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {

        HttpSession session = ((HttpServletRequest) request).getSession();
        String isAdmin = (String) session.getAttribute("isAdmin");

        if (isAdmin == null) {
            ((HttpServletResponse) response).sendRedirect(session.getServletContext().getContextPath() + "/login.jsf");
        } else {
            chain.doFilter(request, response);
        }

    }

    /**
     * @see javax.servlet.Filter#destroy()
     */
    public void destroy() {
        entityManagerFactory = null;
    }
}

AuthManager.java

public class AuthManager implements Filter {

    /** Logger */
    protected Logger log = Logger.getLogger(AuthManager.class.getName());
    private EntityManagerFactory entityManagerFactory;

    /**
     * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
     * @param config
     * @throws javax.servlet.ServletException
     */
    public void init(FilterConfig config) throws ServletException {
    }

    /**
     * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
     * @param request
     * @param response
     * @param chain
     * @throws javax.servlet.ServletException
     * @throws java.io.IOException
     */
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws ServletException, IOException {

        HttpSession session = ((HttpServletRequest) request).getSession();        
        String manager = (String) session.getAttribute("isManager");

        if (manager == null) {
            ((HttpServletResponse) response).sendRedirect(session.getServletContext().getContextPath() + "/login.jsf");
        } else {
            chain.doFilter(request, response);
        }

    }

    /**
     * @see javax.servlet.Filter#destroy()
     */
    public void destroy() {
        entityManagerFactory = null;
    }

12 Respostas

D

Amigo, fazer na “unha” não é nada legal.
Recomendo uma estudada no JAAS, se quiser dificuldade, procurando um tutorial aqui do GUJ ou…usando o Acegi/Spring Security. Neste último caso, olha esse tutorial:

http://ocpsoft.com/java/acegi-spring-security-jsf-login-page/

Creio que vai lhe ajudar muito.
Bons códigos!

A

Vlw, obrigado…
Mas eu queria usar apenas o web.xml sem implementar nada de JAAS… pq minha validação já é feita de outra forma e teria de adaptá-la.

Mas muito obrigado pela sugestão de qualquer forma pois ela foi útil de qualquer jeito. =)

Alguém sabe como implementar isto usando apenas o web.xml ou minhas classes que implementam filtros?

A

Filtros servem pra isso mesmo e devem funcionar pra o que vc deseja.

Vc debugou e tem certeza que qdo o manager loga e volta pra pagina de login nao foi o seu filtro que redirecionou ?
Pq do jeito que esta programado se vc nao conseguir recuperar o valor da sessao (seja pq nao foi gravado ainda, seja pq esta dando qq tipo de problema) vc vai voltar o cara pro login.

Outra coisa se o admin tem que ter acesso a tudo, nos filtros de manager e usuario vc tem que testar se eh perfil admin tbm e deixar passar pro chain.doFilter() :smiley:

/peace

D

Em todo caso, pode ser que ajude. O livro JSF: The Complete Reference possui vários exemplos com segurança. Pega o código e vê:

Bons códigos

A

Aeugenio ou quem puder,

Obrigado pelo toque do admin: realmente estava esquecendo de adicioná-lo na sessão tb de manager. No caso o filtro de admin já está funcionando certinho, faltando agora apenas o de manager que continua sendo redirecionado para a página de login.
No caso do perfil manager eu estou conseguindo sim logar na sessão… o ciclo é executado até após a execução de chain.doFilter(request, response); Porém, o filtro ainda continua redirecionando para a página de login. O que mais poderia ser?

Mais uma vez, obrigado!

A

Pelo que vc ja postou era pra estar funcionando… posta a parte relevante do codigo de autenticacao pra ver se esta faltando algo.

/peace.

A

Vlw pela força Aeugenio…

Eu consegui fazer, mas com uma gambiarra sem sentido e não quero deixar assim, quero deixar bunito… hehe…

Eu não modifiquei nada nos métodos que implementam o filtro e sim, na minha classe de login que irei postar [parte dela] agora:

if (admin != null && cliente == null && usuario == null) {
            //Inserindo flag que existe alguem logado 
            getRequest().getSession().setAttribute("logado", userName);
            //Adicionando no Visit a referencia ao usuário Administrador Corrente
            this.getVisit().setCurrentAdmin(admin);
            //Validando permissão de administrador Geral
            getRequest().getSession().setAttribute("isAdmin", "true");
            this.getVisit().setLoggedAdmin(true);
            this.setErrorMessage(false);
            return "loginAdm";

        } else if (admin == null && cliente != null && usuario == null) {
            //Inserindo flag que existe alguem logado 
            getRequest().getSession().setAttribute("logado", userName);           
             //Adicionando no Visit a referencia ao usuário Cliente Corrente
            this.getVisit().setCurrentClient(cliente);
            //Validando permissão de Cliente/Manager
            getRequest().getSession().setAttribute("isManager", "true");            
[b]        getRequest().getSession().setAttribute("isAdmin", "true"); [/b]           
            this.getVisit().setLoggedClient(true);
            this.setErrorMessage(false);
            return "loginClient";

Logo, no item em negrito (getRequest().getSession().setAttribute(“isAdmin”, “true”):wink: do teste condicional para cliente, quando eu adicionei isto, o perfil de Manager “foi aceito” exibindo a página corretamente ao invés do filtro redirecionar para a tela de login. Porém, como vemos, é um furo do sistema, pois, depois da inserção desta linha, o perfil de cliente vai ter acesso a urls que somente Admin teria. O que não desejamos. Bom, agora, eu preciso saber o que eu posso fazer pra consertar a gambiarra ou fazê-la bunita de vez.

Muito obrigado pela atenção!

A

Cara… sem ofender mas teu codigo ta meio confuso, esse if/elseif no inicio pode te enganar facilmente.

Eu acho que vc devia fazer algo mais simples assim…

  1. Pega user/pass
  2. Testa autenticacao na base - ldap - etc.
  3. Invalido -> 1
  4. Pega perfis do usuario ja autenticado na base
  5. Seta perfis/variaveis na sessao
  6. Retorna pra view qual pagina vc quer que carregue agora (pq provalmente vc esta usando o faces-config pra carregar a proxima pagina)

Outra coisa, eu normalmente tenho um bean de sessao onde coloco tudo o que desejo sem ficar usando propriedades. Tipo assim

MeuBeanDeSessao session = (MeuBeanDeSessao)getRequest().getSessionMap().get("session");
session.setPerfil("adm");
session.setUser(minhaClasseUser);

Dai esse bean (MeuBeanDeSessao) pode ter varios atributos, classes, etc.

/peace

A

Aeugenio,

Nada, sem ofensa nenhuma…

Correlação ao bean de sessão, eu prefiro trabalhar com o desing Pattern Visit mesmo… pq particularmente eu prefiro tratar reponse/request até o JSF ser responsavel por elas. Logo, eu uso um (Visit) getFacesContext().getApplication().createValueBinding("#{visit}").getValue(getFacesContext()) para pegar minhas sessões e deixo meu bean de sessão Visit gerenciá-las. Mas a sua dica tb é muito boa e servirá como uma segundas alternativa sim. E obrigado de qualquer forma…

Eu não compreendi bem uma coisa: o que vc quis dizer com: "4. Pega perfis do usuario ja autenticado na base " ?

Vlw

A

Aeugenio,

eu refatorei melhor meu método de validação como mostrado a seguir. Porem, ainda não esta redirecionando pra pagina certa o perfil de manager ( e a sessao esta identificando um manager direitinho na classe que implementa o respectivo filtro. ). Deve ser uma boberinha que não to conseguindo ver… só pode… E eu retirei a “gambiarra” que tinha feito setando o atributo da sessian “isAdmin” na regra de manager.
Segue o método de validação que fiz:

public String validateLogin() throws NoSuchAlgorithmException {        
        this.cleanVars();
        System.out.println("usuario é:" + this.getUserName() + "senha é:" + this.getPassword());
        if (userName.equals("") || password.equals("")) {
            this.setErrorMessage(true);
            FacesContext context = FacesContext.getCurrentInstance();
            context.addMessage(null, new FacesMessage(Utils.getCustomMessage("errorEmptyLogin", null)));
            return Constantes.RESULTADO_ERRO;
        }
        Administrador admin = AdmDAO.getADMLogin(userName, criptografaSenha(password));
        Cliente cliente = AdmDAO.getClienteLogin(userName, criptografaSenha(password));
        Usuario usuario = AdmDAO.getUsuarioLogin(userName, criptografaSenha(password));
        if (admin != null || cliente != null || usuario != null) {
            getRequest().getSession().setAttribute("logado", userName);
            if (admin != null) {
                this.getVisit().setCurrentAdmin(admin);
                getRequest().getSession().setAttribute("isAdmin", "true");
                this.getVisit().setLoggedAdmin(true);
                return LoginConstantes.ADM_LOGGED;
            } else if (cliente != null) {
                this.getVisit().setCurrentClient(cliente);
                getRequest().getSession().setAttribute("isManager", "true");
                this.getVisit().setLoggedClient(true);
                return LoginConstantes.MANAGER_LOGGED;
            } else {
                this.getVisit().setCurrentUser(usuario);
                getRequest().getSession().setAttribute("isUser", "true");
                this.getVisit().setLoggedUser(true);
                return LoginConstantes.USER_LOGGED;
            }
        } else {
            this.setErrorMessage(true);
            FacesContext context = FacesContext.getCurrentInstance();
            context.addMessage(null, new FacesMessage(Utils.getCustomMessage("errorLogin", null)));
            this.cleanUserPasswd();
        }
        return Constantes.RESULTADO_ERRO;
    }

Segue o AuthManager:

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

        HttpSession session = ((HttpServletRequest) request).getSession();
        String manager = (String) session.getAttribute("isManager");
        String admin = (String) session.getAttribute("isAdmin");

        if (manager == null && admin == null) {
            System.out.println("Manager é null");
            ((HttpServletResponse) response).sendRedirect(session.getServletContext().getContextPath() + "/login.jsf");
        } else {
            System.out.println("Admin é " + admin);
            System.out.println("Manager é " + manager);
            chain.doFilter(request, response);
            System.out.println("Manager é " + manager);
        }
A

Se vc debugou o login e esta retornando o perfil manager corretamento sera que nao é apenas a navegação no faces-config ? Veja se la tem o valor de LoginConstantes.MANAGER_LOGGED

/peace

A

e o pior é que tem… ta tudo certinho… :frowning:

Criado 5 de novembro de 2008
Ultima resposta 6 de nov. de 2008
Respostas 12
Participantes 3