1. 概要

このチュートリアルでは、ユーザーのログインを確認し、ユーザーがログインフォームに有効な資格情報を入力して、セッションを開始したことを確認する方法を学習します。 ただし、これはSpringセキュリティを使用せず、JSPとサーブレットのみを使用して行います。 したがって、Tomcat9のようにそれをサポートできるサーブレットコンテナが必要になります。

最終的には、内部で物事がどのように機能するかをよく理解できるようになります。

2. 永続性戦略

まず、ユーザーが必要です。 簡単にするために、プリロードされたマップを使用します。 Userと一緒に定義しましょう。

public class User {
    static HashMap<String, User> DB = new HashMap<>();
    static {
        DB.put("user", new User("user", "pass"));
        // ...
    }

    private String name;
    private String password;

    // getters and setters
}

3. リクエストのフィルタリング

まず、 filter を作成してセッションレスリクエストをチェックし、サーブレットへの直接アクセスをブロックします。

@WebFilter("/*")
public class UserCheckFilter implements Filter {
    
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
        // ...
        request.setAttribute("origin", request.getRequestURI());

        if (!request.getRequestURI().contains("login") && request.getSession(false) == null) {
            forward(request, response, "/login.jsp");
            return;
        }

        chain.doFilter(request, response);
    }
}

ここで、@ WebFilterのURLパターンとして「/*」を定義することにより、すべてのリクエストが最初にフィルターを通過します。次に、まだセッションがない場合は、リクエストをログインページにリダイレクトし、保存します。後で使用するためのorigin。 最後に、早期に戻り、サーブレットが適切なセッションなしで処理されないようにします。

4. JSPを使用したログインフォームの作成

ログインフォームを作成するには、JSTLからコアTaglibをインポートする必要があります。 また、pageディレクティブでsession属性を「false」に設定しましょう。 その結果、新しいセッションは自動的に作成されず、次のことを完全に制御できます。

<%@ page session="false"%>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%>

<form action="login" method="POST">
    ...
</form>

次に、フォーム内に、originを保存するための非表示の入力があります。

<input type="hidden" name="origin" value="${origin}">

次に、エラーを出力するための条件要素を含めます。

<c:if test="${not empty error}">
    * error: ${error} 
</c:if>

最後に、 input タグをいくつか追加して、ユーザーが資格情報を入力して送信できるようにします。

<input type="text" name="name">
<input type="password" name="password"> 
<input type="submit">

5. ログインサーブレットの設定

サーブレットでは、リクエストが GET の場合、ログインフォームにリクエストを転送します。 そして最も重要なのは、ログインがPOSTであるかどうかを検証することです

@WebServlet("/login")
public class UserCheckLoginServlet extends HttpServlet {
    // ...
}

したがって、 doGet()メソッドでは、ログインJSPにリダイレクトし、originを転送します。

protected void doGet(HttpServletRequest request, HttpServletResponse response) {
    String referer = (String) request.getAttribute("origin");
    request.setAttribute("origin", referer);
    forward(request, response, "/login.jsp");
}

doPost()では、資格情報を検証してセッションを作成し、 User オブジェクトを転送して、originにリダイレクトします。

protected void doPost(HttpServletRequest request, HttpServletResponse response) {
    String key = request.getParameter("name");
    String pass = request.getParameter("password");

    User user = User.DB.get(key);
    if (!user.getPassword().equals(pass)) {
        request.setAttribute("error", "invalid login");
        forward(request, response, "/login.jsp");
        return;
    }
        
    HttpSession session = request.getSession();
    session.setAttribute("user", user);

    response.sendRedirect(request.getParameter("origin"));
}

無効な資格情報の場合、エラー変数にメッセージを設定します。 それ以外の場合は、Userオブジェクトでセッションを更新します。

6. ログイン情報の確認

最後に、ホームページを作成しましょう。 セッション情報が表示され、ログアウトリンクがあります。

<body>
    current session info: ${user.name}

    <a href="logout">logout</a>
</body>

ホームページが行うのは、Userをホームページに転送することだけです。

@WebServlet("/home")
public class UserCheckServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) {
        User user = (User) session.getAttribute("user");
        request.setAttribute("user", user);

        forward(request, response, "/home.jsp");
    }
}

そして、これはそれがどのように見えるかです:

7. ログアウト

ログアウトするには、現在のセッションを無効にして、ホームにリダイレクトします。 その後、 UserCheckFilter がセッションレスリクエストを検出し、ログインページにリダイレクトして、プロセスを再開します。

@WebServlet("/logout")
public class UserCheckLogoutServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) {
        request.getSession().invalidate();

        response.sendRedirect("./");
    }
}

8. 結論

この記事では、完全なログインサイクルの作成について説明しました。 単一のフィルターを使用して、サーブレットへのアクセスを完全に制御できるようになったことを確認しました。 つまり、このアプローチでは、必要な場所に有効なセッションがあることを常に確認できます。 同様に、そのメカニズムを拡張して、より細かいアクセス制御を実装することもできます。

そしていつものように、ソースコードはGitHub利用できます。