認證機制允許用戶通過驗證用戶名和密碼來安全訪問應用程序。我們將在登錄時使用JSF視圖,DAO對象,HttpSession進行會話管理,JSF管理的bean和mysql數據庫。現在讓我們詳細看看如何在JSF應用程序中創建JSF登錄登出認證機制。步驟1: 在mysql數據庫中創建Users表如
CREATE TABLE Users(
uid int(20) NOT NULL AUTO_INCREMENT,
uname VARCHAR(60) NOT NULL,
password VARCHAR(60) NOT NULL,
PRIMARY KEY(uid));
在這裡我們創建用戶表,uid為主鍵,用戶名和密碼字段具有不為空的約束條件。步驟2: 將數據插入到Users表中;
INSERT INTO Users VALUES(1,'adam','adam');
在我們轉向項目相關代碼之前,下面的圖像顯示了Eclipse中的項目結構。只需創建一個動態Web項目,並將其轉換為Maven以獲得項目存根,然後不斷添加不同的組件。 步驟3: 創建JSF登錄頁面
login.xhtml
如;
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="https://www.w3.org/1999/xhtml"
xmlns:h="https://java.sun.com/jsf/html">
<h:head>
<title>login</title>
</h:head>
<h:body>
<h:form>
<h3>JSF Login Logout</h3>
<h:outputText value="Username" />
<h:inputText id="username" value="#{login.user}"></h:inputText>
<h:message for="username"></h:message>
<br></br><br></br>
<h:outputText value="Password" />
<h:inputSecret id="password" value="#{login.pwd}"></h:inputSecret>
<h:message for="password"></h:message>
<br></br><br></br>
<h:commandButton action="#{login.validateUsernamePassword}"
value="Login"></h:commandButton>
</h:form>
</h:body>
</html>
在這裡,我們正在創建一個JSF登錄視圖頁面,具有用戶名和密碼字段,並通過登錄管理的bean設置這些字段的值。我們在單擊登錄按鈕時調用validateUsernamePassword
方法來驗證用戶名和密碼。步驟4: 創建管理的beanLogin.java
如;
package com.journaldev.jsf.beans;
import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpSession;
import com.journaldev.jsf.dao.LoginDAO;
import com.journaldev.jsf.util.SessionUtils;
@ManagedBean
@SessionScoped
public class Login implements Serializable {
private static final long serialVersionUID = 1094801825228386363L;
private String pwd;
private String msg;
private String user;
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
//驗證登錄
public String validateUsernamePassword() {
boolean valid = LoginDAO.validate(user, pwd);
if (valid) {
HttpSession session = SessionUtils.getSession();
session.setAttribute("username", user);
return "admin";
} else {
FacesContext.getCurrentInstance().addMessage(
null,
new FacesMessage(FacesMessage.SEVERITY_WARN,
"Incorrect Username and Passowrd",
"Please enter correct username and Password"));
return "login";
}
}
//登出事件,使會話失效
public String logout() {
HttpSession session = SessionUtils.getSession();
session.invalidate();
return "login";
}
}
我們宣告三個String變數user、pwd和msg,分別用於用戶名、密碼和錯誤消息字段,並提供getter和setter方法。我們編寫一個方法validateUsernamePassword()來驗證用戶名和密碼字段,通過調用LoginDAO類從數據庫中獲取用戶名和密碼並與前端傳遞的值進行比較。如果用戶名和密碼不匹配,則顯示錯誤消息為“用戶名和密碼不正確”。同時,編寫了一個logout()方法來執行登出操作,使HTTPSession無效。第5步: 現在創建LoginDAO java類如下。請注意,數據庫操作代碼並未優化,無法用於實際項目中,我盡快編寫它,因為想要學習JSF應用程序中的身份驗證。
package com.journaldev.jsf.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.journaldev.jsf.util.DataConnect;
public class LoginDAO {
public static boolean validate(String user, String password) {
Connection con = null;
PreparedStatement ps = null;
try {
con = DataConnect.getConnection();
ps = con.prepareStatement("Select uname, password from Users where uname = ? and password = ?");
ps.setString(1, user);
ps.setString(2, password);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
//result found, means valid inputs
return true;
}
} catch (SQLException ex) {
System.out.println("Login error -->" + ex.getMessage());
return false;
} finally {
DataConnect.close(con);
}
return false;
}
}
在validate()方法中,我們首先通過調用DataConnect類的getConnection方法建立與數據庫的連接。我們使用PreparedStatement來構建查詢,以使用者輸入的值從數據庫中獲取數據。如果在結果集中獲取到任何數據,則意味著輸入有效,我們返回true,否則返回false。第6步: 創建DataConnect.java類如下;
package com.journaldev.jsf.util;
import java.sql.Connection;
import java.sql.DriverManager;
public class DataConnect {
public static Connection getConnection() {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/cardb", "pankaj", "pankaj123");
return con;
} catch (Exception ex) {
System.out.println("Database.getConnection() Error -->"
+ ex.getMessage());
return null;
}
}
public static void close(Connection con) {
try {
con.close();
} catch (Exception ex) {
}
}
}
我們使用Class.forName
方法加載JDBC驅動程序,並使用DriverManager.getConnection
方法傳遞URL、用戶名和密碼來連接到數據庫。 步驟 7:創建SessionUtils.java來獲取和管理與用戶信息相關的會話。
package com.journaldev.jsf.beans;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
public class SessionUtils {
public static HttpSession getSession() {
return (HttpSession) FacesContext.getCurrentInstance()
.getExternalContext().getSession(false);
}
public static HttpServletRequest getRequest() {
return (HttpServletRequest) FacesContext.getCurrentInstance()
.getExternalContext().getRequest();
}
public static String getUserName() {
HttpSession session = (HttpSession) FacesContext.getCurrentInstance()
.getExternalContext().getSession(false);
return session.getAttribute("username").toString();
}
public static String getUserId() {
HttpSession session = getSession();
if (session != null)
return (String) session.getAttribute("userid");
else
return null;
}
}
在這裡,我們通過getUserId方法為每個登錄的用戶獲取一個會話,從而將會話ID與特定用戶ID關聯起來。 步驟 8:創建授權過濾器類如下;
package com.journaldev.jsf.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebFilter(filterName = "AuthFilter", urlPatterns = { "*.xhtml" })
public class AuthorizationFilter implements Filter {
public AuthorizationFilter() {
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
HttpServletRequest reqt = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
HttpSession ses = reqt.getSession(false);
String reqURI = reqt.getRequestURI();
if (reqURI.indexOf("/login.xhtml") >= 0
|| (ses != null && ses.getAttribute("username") != null)
|| reqURI.indexOf("/public/") >= 0
|| reqURI.contains("javax.faces.resource"))
chain.doFilter(request, response);
else
resp.sendRedirect(reqt.getContextPath() + "/faces/login.xhtml");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
@Override
public void destroy() {
}
}
我們通過重寫destroy和doFilter方法來實現標準過濾器類。在doFilter方法中,如果用戶未登錄,我們將重定向用戶到登錄頁面。 步驟 9:創建admin.xhtml
如下;
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="https://www.w3.org/1999/xhtml"
xmlns:h="https://java.sun.com/jsf/html">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<h:form>
<p>Welcome #{login.user}</p>
<h:commandLink action="#{login.logout}" value="Logout"></h:commandLink>
</h:form>
</h:body>
</html>
此頁面在用戶成功登錄時呈現。登出功能通過調用Login.java
類的logout方法來實現。 步驟 10:創建faces-config.xml
文件如下;
<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.2" xmlns="https://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://xmlns.jcp.org/xml/ns/javaee
https://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">
<navigation-rule>
<from-view-id>/login.xhtml</from-view-id>
<navigation-case>
<from-outcome>admin</from-outcome>
<to-view-id>/admin.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
完成上述指定步驟後,運行應用程序,並在瀏覽器中查看以下輸出:登錄頁面 身份驗證錯誤頁面
登錄成功頁面
在已登錄狀態下訪問 admin.xhtml
只需點擊登出鏈接,會使會話失效,然後嘗試訪問 admin.xhtml 頁面,您將被重定向到登錄頁面,請隨時從以下鏈接下載項目並嘗試:
Source:
https://www.digitalocean.com/community/tutorials/jsf-authentication-login-logout-database-example