Pergunta

Eu estou querendo saber o que a abordagem atual é sobre a autenticação do usuário para uma aplicação web fazendo uso de JSF 2.0 (e se algum dos componentes não existem) e Java EE 6 mecanismos centrais (permissões de login / cheque / logouts) com mantenha as informações do usuário numa entidade JPA. O tutorial do Oracle Java EE é uma escassa pouco sobre isso (só lida servlets).

Esta é sem fazendo uso de toda uma outra estrutura, como Primavera-Security (Acegi), ou Seam, mas tentando furar espero que com o novo Java EE 6 plataforma (perfil web) se possível .

Foi útil?

Solução

Depois de pesquisar na Web e tentar muitas maneiras diferentes, aqui está o que eu sugiro para Java EE 6 de autenticação:

Configurar o domínio de segurança:

No meu caso, eu tinha os usuários no banco de dados. Então, eu seguido este blog para criar um Realm JDBC que pode autenticar usuários com base em nome de usuário e MD5-hash senhas em minha mesa banco de dados:

http: //blog.gamatam. cOM / 2009/11 / jdbc-reino-setup-com-glassfish-v3.html

Nota: as negociações post sobre um usuário e uma mesa de grupo no banco de dados. Eu tive uma classe de usuário com um atributo UserType enum mapeado através de anotações javax.persistence ao banco de dados. Eu configurei o reino com a mesma mesa para usuários e grupos, utilizando a coluna userType como a coluna de grupo e funcionou muito bem.

Use autenticação de formulário:

Ainda seguindo o post acima, configure seu web.xml e sun-web.xml, mas em vez de usar a autenticação básica, o uso FORM (na verdade, não importa qual você usa, mas acabei usando FORM ). Use o HTML padrão, não o JSF.

Em seguida, use a ponta de BalusC acima de preguiçoso inicializar as informações do usuário do banco de dados. Ele sugeriu fazê-lo em um bean gerenciado ficando o principal a partir do contexto rostos. I utilizado, em vez disso, um bean de sessão com informações de estado para armazenar informações de sessão para cada usuário, de modo que injetou o contexto da sessão:

 @Resource
 private SessionContext sessionContext;

Com o principal, eu posso verificar o nome de usuário e, usando o EJB Entity Manager, obter informações do usuário do banco de dados e armazenar em minha SessionInformation EJB.

Sair:

Eu também olhei em volta para a melhor maneira de sair. O melhor que eu encontrei está usando um servlet:

 @WebServlet(name = "LogoutServlet", urlPatterns = {"/logout"})
 public class LogoutServlet extends HttpServlet {
  @Override
  protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
   HttpSession session = request.getSession(false);

   // Destroys the session for this user.
   if (session != null)
        session.invalidate();

   // Redirects back to the initial page.
   response.sendRedirect(request.getContextPath());
  }
 }

Embora a minha resposta é muito tarde considerando a data de questão, eu espero que isso ajude outras pessoas que acabam aqui do Google, assim como eu fiz.

Ciao,

Vítor Souza

Outras dicas

Eu suponho que você quer usando descritores de implantação e j_security_check.

Você também pode fazer isso no JSF apenas usando o mesmo predefinied nomes de campos j_username e j_password como demonstrado no tutorial.

por exemplo.

<form action="j_security_check" method="post">
    <h:outputLabel for="j_username" value="Username" />
    <h:inputText id="j_username" />
    <br />
    <h:outputLabel for="j_password" value="Password" />
    <h:inputSecret id="j_password" />
    <br />
    <h:commandButton value="Login" />
</form>

Você poderia fazer o carregamento lento no getter User para verificar se o User já está conectado e se não, em seguida, verificar se o Principal está presente no pedido e, se assim for, então obter o User associado com j_username.

package com.stackoverflow.q2206911;

import java.io.IOException;
import java.security.Principal;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;

@ManagedBean
@SessionScoped
public class Auth {

    private User user; // The JPA entity.

    @EJB
    private UserService userService;

    public User getUser() {
        if (user == null) {
            Principal principal = FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
            if (principal != null) {
                user = userService.find(principal.getName()); // Find User by j_username.
            }
        }
        return user;
    }

}

O User é obviamente acessível em JSF EL por #{auth.user}.

Para Sair fazer um HttpServletRequest#logout() (e conjunto User como nulo!). Você pode obter uma alça do HttpServletRequest em JSF por ExternalContext#getRequest() . Você também pode simplesmente invalidar a sessão completamente.

public String logout() {
    FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
    return "login?faces-redirect=true";
}

Para o remanescente (definir usuários, funções e limitações em descritor de implementação e reino), basta seguir o Java EE 6 tutorial e documentação servletcontainer da maneira usual.


Atualizar : você pode também usar o novo Servlet 3.0 HttpServletRequest#login() fazer um login programático em vez de usar j_security_check que pode não per-se ser acessível por um Dispatcher em alguns servletcontainers. Neste caso, você pode usar uma forma fullworthy JSF e um feijão com username e password propriedades e um método login que esta aparência:

<h:form>
    <h:outputLabel for="username" value="Username" />
    <h:inputText id="username" value="#{auth.username}" required="true" />
    <h:message for="username" />
    <br />
    <h:outputLabel for="password" value="Password" />
    <h:inputSecret id="password" value="#{auth.password}" required="true" />
    <h:message for="password" />
    <br />
    <h:commandButton value="Login" action="#{auth.login}" />
    <h:messages globalOnly="true" />
</h:form>

E esta visão escopada bean gerenciado que também lembra a página inicialmente solicitado:

@ManagedBean
@ViewScoped
public class Auth {

    private String username;
    private String password;
    private String originalURL;

    @PostConstruct
    public void init() {
        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
        originalURL = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_REQUEST_URI);

        if (originalURL == null) {
            originalURL = externalContext.getRequestContextPath() + "/home.xhtml";
        } else {
            String originalQuery = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_QUERY_STRING);

            if (originalQuery != null) {
                originalURL += "?" + originalQuery;
            }
        }
    }

    @EJB
    private UserService userService;

    public void login() throws IOException {
        FacesContext context = FacesContext.getCurrentInstance();
        ExternalContext externalContext = context.getExternalContext();
        HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();

        try {
            request.login(username, password);
            User user = userService.find(username, password);
            externalContext.getSessionMap().put("user", user);
            externalContext.redirect(originalURL);
        } catch (ServletException e) {
            // Handle unknown username/password in request.login().
            context.addMessage(null, new FacesMessage("Unknown login"));
        }
    }

    public void logout() throws IOException {
        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
        externalContext.invalidateSession();
        externalContext.redirect(externalContext.getRequestContextPath() + "/login.xhtml");
    }

    // Getters/setters for username and password.
}

Desta forma, o User é acessível em JSF EL por #{user}.

Deve-se mencionar que é uma opção para deixar completamente problemas de autenticação para o controlador de frente, por exemplo, um servidor web Apache e avaliar o HttpServletRequest.getRemoteUser () em vez disso, que é a representação JAVA para a variável de ambiente REMOTE_USER. Isto permite também log sofisticados em projetos como a autenticação Shibboleth. Filtrar solicitações para um servlet container através de um servidor web é um bom design para ambientes de produção, muitas vezes mod_jk é usado para fazê-lo.

A questão HttpServletRequest.login não definir o estado de autenticação em sessão foi corrigido em 3.0.1. Atualização do GlassFish para a versão mais recente e está feito.

A atualização é bastante simples:

glassfishv3/bin/pkg set-authority -P dev.glassfish.org
glassfishv3/bin/pkg image-update
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top