JSF認証ログインログアウトデータベースの例

認証メカニズムにより、ユーザーはユーザー名とパスワードを検証することで、アプリケーションへの安全なアクセスを持つことができます。ログインには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を主キーとし、usernameとpasswordフィールドにはnot null制約があるユーザーテーブルを作成します。 ステップ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";
	}
}

ユーザー名、パスワード、エラーメッセージのフィールドのために、user、pwd、msgという3つの文字列変数を宣言し、それぞれのゲッターとセッターメソッドを記述します。フロントエンドで渡された値とデータベースから取得したユーザー名とパスワードを比較するためにLoginDAOクラスを呼び出すことで、ユーザー名とパスワードのフィールドを検証するためのvalidateUsernamePassword()メソッドを記述します。ユーザー名とパスワードが一致しない場合は、「ユーザー名とパスワードが間違っています」というエラーメッセージが表示されます。また、HTTPセッションを無効にすることでログアウトを行うlogout()メソッドも記述されています。Step 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()) {
				//結果が見つかった場合、有効な入力を意味します。
				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を返します。Step 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) {
		}
	}
}

JDBC ドライバClass.forNameメソッドを使用してロードし、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 メソッドでは、ログインせずに他のページにアクセスしようとした場合に、ユーザーをログインページにリダイレクトします。 ステップ 9admin.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 メソッドを呼び出すことによって実装されます。 ステップ 10faces-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ページにアクセスしようとすると、ログインページにリダイレクトされます。以下のリンクからプロジェクトをダウンロードして試してみてください。

JSF認証ログインログアウトプロジェクトをダウンロード

Source:
https://www.digitalocean.com/community/tutorials/jsf-authentication-login-logout-database-example