Tenho um form de login:
[code]<h:form id=“login_form”>
<h2><h:outputText value="Login" /></h2>
<p id="primeiro">
<h:outputText value="Login" />
<h:inputText id="login" size="25" maxlength="15"
required="true" value="#{usuarioBean.login}" >
<f:validator validatorId="validaLogin"/>
</h:inputText>
<h:message styleClass="erro" for="login" />
</p>
<p>
<h:outputText value="Senha" />
<h:inputSecret id="senha" size="25" value="#{usuarioBean.senha}" >
<f:validator validatorId="validaSenha"/>
</h:inputSecret>
<h:message styleClass="erro" for="senha" />
</p>
<p>
<h:commandButton action="#{usuarioBean.checaLogin}" styleClass="botao" id="enviar"
value="Entrar" type="submit">
</h:commandButton>
</h:form>[/code]
Criei um validador ‘validaLogin’ para ver se o login existe no banco de dados e queria usar o ‘validaSenha’ para testar se o login está correto, mas não estou conseguindo pegar os dois campos (login e senha) para checar o login, o meu método validade está assim:
[code]
public void validate(FacesContext context, UIComponent component,
Object value) throws ValidatorException {
String loginIn = (String)component.getAttributes().get(“login”);
UIInput loginInput = (UIInput) context.getViewRoot().findComponent(loginIn);
String login = (String) loginInput.getValue();
String senha = (String) value;
UsuarioDAO dao = new UsuarioDAO();
Map sessao = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
if (!dao.checaLogin(login, senha, sessao)) {
FacesMessage message = new FacesMessage();
message.setDetail("Senha inválida!");
message.setSummary("Login Invalido!");
message.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(message);
}
}[/code]
Qual a forma certa de fazer isso?
Olá,
Você pode fazer o teste em um action e retornar a regra de navegação para a mesma página caso o login não seja satisfeito.
Sua solução não é ruim, mas vá de action que não tem erro.
Abraço
Na verdade os Validators do JSF ñ suportam Cross Field Validation, talvez no 2.1 :). De qualquer forma essa ñ parece mesmo a melhor maneira de implementar esse caso. Me parece mais coerente (e simples tb) q vc trate a autênticação como uma funcionalidade e use um ManagedBean p/ isso:
@Named
@RequestScoped
public class Authenticator {
private String username;
private String password;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return null; } // Vc ñ vai querer expor a senha do usuário, vai?
public void setPassword(String password) { this.password = password; }
public void login() {
// Aqui vc coloca a sua lógica de autênticação.
}
}
Eu faria a seguinte alteração no código do dev.rafael:
String login(){}
Vlw pessoal! Funcionou beleza, eu coloquei assim:
public String checaLogin(){
UsuarioDAO dao = new UsuarioDAO();
Map sessao = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
if(dao.checaLogin(login, senha, sessao)){
return "sucesso";
}
else if(!dao.existeUsuario(login, sessao)){
FacesMessage message = new FacesMessage("Login inválido");
message.setSeverity(FacesMessage.SEVERITY_ERROR);
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Login inválido", null));
}else{
FacesMessage message = new FacesMessage("Senha inválido");
message.setSeverity(FacesMessage.SEVERITY_ERROR);
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Senha inválida", null));
}
return "falha";
}
E alterei na página para <h:messages/>, só queria saber o que teria que alterar para poder apresentar as mensagens individualmente, tipo <h:message for=“login” />
Tranquilo, acontece.
Tenho acompanhado os foruns e você é uma pessoa que contribui em muito com respostas bem elaboradas.
Abraço
Em geral é um pouco melhor vc usar uma menssagem do tipo “Login ou senha inválida”, afinal vc ñ quer dar dicas à um possível hacker q está tentando hackear uma conta, ñ é?
Outra coisa, se vc estiver usando JPA, então o padrão DAO na sua aplicação é dispensável. Isso pq a class EntityManager do JPA te provê todos os benefícios de um DAO. Somente com o uso do EntityManager e a eliminação dos DAOs é q vc consegue uma arquitetura realmente MVC.
Não tinha pensado nisso, vlw!
Ah, e quanto ao DAO, eu estou usando porque estou fazendo este projeto para estudar, a princípio, somente o JSF, então estou armazenando o Banco de Dados em um Map na sessão mas quando eu começar a utilizar algum BD eu vou levar o JPA em conta
Obrigado pela ajuda e as dicas.
Só mais um detalhe. Use constantes p/ representar as suas regras de navegação. Um padrão q tem me ajudado muito é o seguinte:
public final class NavigationRule {
public static final NavigationRule LOGIN_SUCCESS = new NavigationRule("success");
public static final NavigationRule LOGIN_FAIL = new NavigationRule("fail");
private String name;
private NavigationRule(String name) { this.name = name; }
public NavigationRule redirect() { return new NavigationRule(name + "?faces-redirect=true"); }
@Override
public String toString() { return name; }
}
Nos seus ManagedBeans vc, então pode:
import NavigationRules;
import static NavigationRules.*;
@Named
@RequestScoped
public class Authenticator {
public NavigationRule login() {
return LOGIN_SUCCESS.redirect();
}
}
Interessante! Como funciona esse faces-redirect=true ?
Essa é uma funcionalidade nova no JSF 2, chamase implicit navigation. Até o JSF 1.2 vc precisava registrar todas as suas navigation rules no faces-config.xml. Já no JSF 2 basta q vc retorne o nome do arquivo p/ onde vc quer navegar sem a extenção (nome é caminho, é claro). P/ fazer redirecionamentos (q até o JSF 1.2 usavam ) vc só precisa adicionar o parametro faces-redirect=true à sua navigation-rule.