我正在使用JSF 2.0开发一个Web应用程序。我通过托管bean(LoginHandler)实现了登录,并检查用户是否使用过滤器登录。
现在,通过发送带有用户名和密码作为参数的请求,我得到了能够登录应用程序的请求。哪种方法最好?
我尝试使用f:metadata和preRenderView事件,但似乎过滤器是更好的解决方案吗?我也尝试在登录页面的url上编写HTTPFilter,但问题是我需要将用户数据存储在我的托管bean中,当我第一次访问应用程序时,我没有从中获取管理bean的会话。
Otpion 1:f:managedbean LoginHandler中的元数据和操作: 登录页面:
<f:metadata>
<f:viewParam name="username" value="#{loginManager.username}"/>
<f:viewParam name="password" value="#{loginManager.password}"/>
<f:event type="preRenderView" listener="#{loginManager.singleSignOn}"/>
</f:metadata>
LoginHandler中的singleSignOn方法检查是否设置了用户名和密码。如果是这种情况,它的作用与提交登录表单相同(它使用相同的方法),如果登录成功,则转发到欢迎页面。否则返回null(显示登录页面)
Otpion 2:过滤器:
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
String username = request.getParameter("username");
String password = request.getParameter("password");
LoginHandler loginHandler = null;
if (session != null) {
loginHandler = (LoginHandler) session.getAttribute("loginHandler");
if (loginHandler != null && username != null && password != null) {
boolean loginOk = false;
//do logic using methods and objects in loginHandler and set loginOk if login is successful
loginOk = loginHandler.login(username, password);
if (loginOk) {
// login OK
response.sendRedirect(request.getContextPath() + WELCOME_PAGE_URL);
}
}
}
chain.doFilter(request, response);
}
如上所述,选项2的问题是我第一次访问应用程序时没有设置会话(即,我需要尝试登录两次 - 第二次一切正常)
由于
EDIT1:更新了评论和说明,以更好地反映类LoginHandler的作用
答案 0 :(得分:3)
关于何时使用 f:param
& f:metadata
,我建议您阅读
这个答案作为一个伟大的答案提供了这样的。由于数据是通过f:viewParam
请求发送的,因此永远不要使用HTTP GET
来处理用户输入。
还建议不要将servlets
与JSF
申请一起使用
会话范围的bean是HTTPSessions
的属性,你会发现
解释为什么here。
最后有四种方法可以在一个系统中注册一个系统甚至列表器
JSF应用程序。
使用您在问题中使用的f:event
标记
提供,通过注释类
@ListnerFor(systemEventClass = typeOfEvent.class)
,通过拨打电话
subscribeToEvent
方法,最后注册一个系统事件
faces-config.xml
文件中的列表器如此
<application>
<system-event-listener>
<system-event-listener-class>listenerClass</system-event-listener-class>
<system-event-class>eventClass</system-event-class>
</system-event-listener>
</application>
在您使用f:event
标记的情况下(正如您在问题中所做的那样),您应该确保将其括在f:view
标记中
<f:view>
<f:event type="preRenderView" listener="#{loginManager.singleSignOn}"/>
......
<f:viewParam name="username" value="#{loginManager.username}"/>
<f:viewParam name="password" value="#{loginManager.password}"/>
......
</f:view>
并且你的bean方法接受ComponentSystemEvent
如此
public void singleSignOn(ComponentSystemEvent event) {
if (!login) {
//do JSF stuff here when validating credentials fails or passes
//eg. perform navigation
}
}
注意:这个问题的答案解决了如何使用jsf实现过滤器,use it as head start
对于其他材料,我建议您继续Basic steps for starting session in jsf。
答案 1 :(得分:0)
我参加了prerenderview
活动:
singleSignOn.xhtml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<f:metadata>
<f:viewParam name="userName" value="#{loginCredentials.userName}" />
<f:viewParam name="password" value="#{loginCredentials.password}" />
<f:event type="preRenderView" listener="#{loginHandler.singleSignOn}" />
</f:metadata>
<h:head>
<title>singleSignOn</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</h:head>
<h:body />
</html>
LoginCredentials是一个请求范围的POJO,其字段为userName和password。
LoginHandler中的singleSignOn()(部分):
public void singleSignOn(ComponentSystemEvent event) {
if (loginCredentials.getUserName() != null
&& loginCredentials.getPassword() != null) {
login();
} else {
// error handling (i did output on syserr)
}
}
LoginCredentials和LoginHandler.login是绑定到登录页面上h:form
的相同bean /方法