cho*_*o70 3 jsf message login spring-security
我在我的jsf2网络应用程序中使用spring security 3.
如何在登录表单中显示错误的凭据消息,而不将get param?login_error附加到authenticated-fail-login-page?
我尝试过使用像本教程这样的阶段监听器:
http://tutorials.slackspace.de/tutorial/Custom-login-page-with-JSF-and-Spring-Security-3
但它不起作用.
没有preRenderView监听器.
并且既不检查弹簧安全性最后一个异常以呈现消息.
有任何想法吗?
更新:
我的登录页面:
<f:metadata>
<f:viewParam name="error" value="#{autenticacionController.error}" />
<f:event listener="#{autenticacionController.comprobarAuthException}" type="preRenderView" />
</f:metadata>
<h:messages globalOnly="true" layout="table" />
<h:form id="formLogin" prependId="false">
<h:outputLabel for="j_username" value="Usuario:" />
<h:inputText id="j_username" value="#{autenticacionController.administrador.login}" />
<h:outputLabel for="j_password" value="Contraseña:" />
<h:inputSecret id="j_password" value="#{autenticacionController.administrador.password}" />
<h:commandButton value="Entrar" action="#{autenticacionController.loginAction}" />
<h:commandButton value="Cancelar" immediate="true" action="#{autenticacionController.cancelarAction}" />
</h:form>
Run Code Online (Sandbox Code Playgroud)
我的托管bean:
@ManagedBean(name="autenticacionController")
@RequestScoped
public class AutenticacionController extends BaseController {
//entidad "administrador" contra el que validar los campos del form login
private Administrador administrador = new Administrador();
//propiedad de spring-security (true si el usuario no es anónimo)
@SuppressWarnings("unused")
private boolean autenticado;
//propiedad para guardar el param GET si hubo fallo en la autenticación de SS
private int error;
//Constructor vacío del Backing Bean controlador
public AutenticacionController() {
log.info("Creación del backing bean AutenticacionController");
}
@PostConstruct
public void init() {
//inicializar atributos del backing bean
log.info("PostConstruct del backing bean BarcoController");
}
//Getters y setters de atributos del backing bean
public Administrador getAdministrador() {
return administrador;
}
public void setAdministrador(Administrador administrador) {
this.administrador = administrador;
}
public boolean isAutenticado() {
Authentication autenticacion = SecurityContextHolder.getContext().getAuthentication();
boolean resultado = (autenticacion != null) &&
!(autenticacion instanceof AnonymousAuthenticationToken) &&
autenticacion.isAuthenticated();
return resultado;
}
public int getError() {
return error;
}
public void setError(int error) {
this.error = error;
}
//MÉTODO LISTENER del evento preRenderView en la página login.
//Para comprobar si la autenticación de Spring Security falló (error=1).
//En ese caso muestra el error con un faces message.
public void comprobarAuthException (ComponentSystemEvent event){
log.info("listener comprobarAuth");
if (error==1) {
String msj = "";
Exception e = (Exception) UtilJsf.getParamSessionMap(WebAttributes.AUTHENTICATION_EXCEPTION);
log.info("SSexception = "+((e==null)?"null":e.getMessage()));
if (e != null) {
String ultimoUsuario = (String) UtilJsf.getParamSessionMap(WebAttributes.LAST_USERNAME);
log.info("SS last_username = "+ultimoUsuario);
administrador.setLogin(ultimoUsuario);
if (e instanceof BadCredentialsException) {
msj = UtilJsf.getMsjProperties("msjsInfo", "UsuPwdIncorrectos");
} else {
msj = UtilJsf.getMsjProperties("msjsInfo", "ErrorAutenticacion");
}
UtilJsf.mostrarFacesMsjGlobal(msj);
}
}
return;
}
/* ******************************* */
/* Métodos "action" del form login */
/* ******************************* */
// EVENTO: Pulsar el botón "entrar" del form login
// Reenviar(FORWARD) la petición a la URL "/j_spring_security_check" para autenticarse
// También se debe configurar el filtro de spring-security para que procese forwards
public void loginAction () {
try {
FacesContext.getCurrentInstance().getExternalContext().dispatch("/j_spring_security_check");
} catch (IOException e) {
}
}
// EVENTO: Pulsar el boton "cancelar" en el form login
// No hacer nada --> Ir a la pantalla de inicio de la aplic
public String cancelarAction () {
return "/inicio";
}
}
Run Code Online (Sandbox Code Playgroud)
在我的Spring Security配置中,我有:
authentication-failure-url="/faces/paginas/autenticacion/login.xhtml?error=1"
Run Code Online (Sandbox Code Playgroud)
如果我从登录页面中删除了错误参数和viewParam,并且在监听器中我只检查了Spring Security异常,它就不起作用了.
感谢退出,我的方法类似,我有以下链接:
<h:outputLink value="#{request.contextPath}/j_spring_security_logout" rendered="#{autenticacionController.autenticado}">Cerrar sesión (Administrador)</h:outputLink>
Run Code Online (Sandbox Code Playgroud)
我倾向于使用<f:event>preRenderView来更新表单上的消息组件.这就是我做到的.
<f:event listener="#{loginBean.updateMessages(true)}" type="preRenderView" />
<div style="margin-left: 50px; width: 500px;"><br />
<h:form id="loginForm" prependId="false">
<p:messages id="errorMessages" />
<label for="j_username">
<h:outputText value="Username:" /><br />
</label>
<h:inputText id="j_username" required="true" width="500" style="width: 300px;" />
<br />
<br />
<label for="j_password">
<h:outputText value="Password:" /><br />
</label>
<h:inputSecret id="j_password" required="true" width="500" style="width: 300px;" />
<h:link value="Forgot my password" outcome="forgotpassword" />
<br />
<br />
<label for="_spring_security_remember_me">
<h:outputText value="Remember me" />
</label>
<h:selectBooleanCheckbox id="_spring_security_remember_me" />
<br /><br />
<p:commandButton ajax="false" type="submit" id="login" action="#{loginBean.doLogin}" value="Login" update="errorMessages" />
</h:form>
</div>
Run Code Online (Sandbox Code Playgroud)
然后在我的LoginBean托管bean中,我将请求转发到Spring Security servlet,并更新消息.如果您有兴趣了解我是如何处理该问题的,您会注意到我还有退出操作的代码.
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(final String username) {
this.username = username.trim();
}
public String getPassword() {
return password;
}
public void setPassword(final String password) {
this.password = password.trim();
}
public void updateMessages(boolean update) throws Exception {
System.out.println("Start LoginBean.updateMessages");
ex = (Exception)FacesContext.getCurrentInstance().getExternalContext().getSessionMap()
.get(WebAttributes.AUTHENTICATION_EXCEPTION);
if (ex != null) {
log.error("Authentication Failed! ", ex);
System.err.println("Authentication Failed! " + ex.getMessage());
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_ERROR, ex.getMessage(), ex.getMessage()));
}
System.out.println("End LoginBean.updateMessages");
}
public String doLogin() {
log.info("Start LoginBean.doLogin");
try {
ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
RequestDispatcher dispatcher = ((ServletRequest) context.getRequest())
.getRequestDispatcher("/j_spring_security_check");
dispatcher.forward((ServletRequest) context.getRequest(),
(ServletResponse) context.getResponse());
FacesContext.getCurrentInstance().responseComplete();
// It's OK to return null here because Faces is just going to exit.
} catch (Exception e) {
log.error("Exception doLogin", e);
} finally {
log.info("End LoginBean.doLogin");
}
return "";
}
public String logout() {
FacesContext context = FacesContext.getCurrentInstance();
Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
if (!sessionMap.containsKey("sessionBean"))
return "";
SessionBean sessionBean = (SessionBean)sessionMap.get("sessionBean");
log.info("Logging out user: " + sessionBean.getLoggedInUser().getUsername());
sessionMap.remove("sessionBean");
//HttpSession session = (HttpSession)context.getExternalContext().getSession(false);
//session.invalidate();
RequestDispatcher dispatcher = ((ServletRequest) context.getExternalContext().getRequest())
.getRequestDispatcher("/j_spring_security_logout");
try {
dispatcher.forward((ServletRequest) context.getExternalContext().getRequest(),
(ServletResponse) context.getExternalContext().getResponse());
} catch (ServletException e) {
log.error("ServletException", e);
} catch (IOException e) {
log.error("IOException", e);
}
FacesContext.getCurrentInstance().responseComplete();
// It's OK to return null here because Faces is just going to exit.
log.info("End LoginBean.logout");
return "";
}
public boolean isLoggedIn() {
FacesContext context = FacesContext.getCurrentInstance();
Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
return sessionMap.containsKey("sessionBean");
}
Run Code Online (Sandbox Code Playgroud)
编辑:
我想我现在更能理解你的问题了.我记得我也无法让它工作,所以基本上我必须编写自己的类来实现AuthenticationFailureHandler并正确实现该方法:
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException ex) throws IOException, ServletException {
//Do business logic stuff, logging, etc...
request.getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, ex);
response.sendRedirect("login.xhtml");
Run Code Online (Sandbox Code Playgroud)
基本上你看到我正在实例化一个异常并将其设置为一个会话属性,以便稍后在我的托管bean中可以检索并转换为一个FacesMessage.
您还必须将此声明AuthenticationFailureHandler为Spring Security配置文件中的身份验证失败事件的自定义处理程序(请注意,我还显示我对身份验证成功处理程序执行相同的操作,但您可能想要也可能不想这样做以及).
<form-login login-page="/login.xhtml" login-processing-url="/j_spring_security_check"
authentication-success-handler-ref="authenticationSuccessBean"
authentication-failure-handler-ref="authenticationFailureBean" />
...
<beans:bean id="authenticationFailureBean" class="com.maple.controllers.FailureHandler">
<beans:property name="userBo" ref="userController" /> <!-- Just injecting my BL layer... -->
</beans:bean>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7913 次 |
| 最近记录: |