Javaにおけるセッション管理は、Servlet Webアプリケーションにおける非常に興味深いトピックです。Javaにおけるセッションは、Cookie、HttpSession API、URL書き換えなど、さまざまな方法で管理されます。これはJavaのWebアプリケーションチュートリアルシリーズの3番目の記事です。前の2つの記事もチェックしてみてください。
Javaにおけるセッション管理
この記事は、異なる技術を使用したサーブレットにおけるセッション管理について説明し、例プログラムを示すことを目的としています。
-
セッションとは何ですか?
HTTPプロトコルとWebサーバーは状態を保持しないため、Webサーバーにとっては各リクエストが新しいリクエストであり、以前にリクエストを送信してきたクライアントかどうかを識別することができません。しかし、Webアプリケーションでは、クライアントが誰であるかを知ってリクエストを適切に処理する必要がある場合があります。たとえば、ショッピングカートアプリケーションでは、アイテムを追加するリクエストを送信しているユーザーが誰であるか、およびアイテムを追加するカートがどれであるか、またはチェックアウトリクエストを送信しているユーザーが誰であるかを知る必要があります。そうすることで、適切なクライアントに金額を請求できます。セッションは、クライアントとサーバーの間の対話状態であり、クライアントとサーバーの間で複数のリクエストとレスポンスが含まれることがあります。HTTPとWebサーバーの両方が状態を保持しないため、セッションを維持する唯一の方法は、セッションに関する一意の情報(セッションID)をリクエストとレスポンスの間でサーバーとクライアントの間で渡すことです。リクエストとレスポンスで一意の識別子を提供するいくつかの方法があります。
-
ユーザー認証 – これは非常に一般的な方法であり、ユーザーはログインページから認証情報を提供し、その後、セッションを維持するためにサーバーとクライアント間で認証情報を渡すことができます。これは同じユーザーが異なるブラウザからログインしている場合には機能しないため、効果的な方法ではありません。
-
HTMLの隠しフィールド – HTMLに一意の隠しフィールドを作成し、ユーザーがナビゲーションを開始すると、その値をユーザーごとに一意に設定し、セッションを追跡できます。この方法はリンクとは使用できません。なぜなら、リクエストがクライアントからサーバーに送信されるたびにフォームを送信する必要があるためです。また、HTMLソースから隠しフィールドの値を取得してセッションをハッキングすることができるため、セキュリティが確保されていません。
-
URLの書き換え – リクエストごとにセッション識別子パラメータを追加して追跡できます。これは非常に手間がかかります。なぜなら、このパラメータをすべてのレスポンスで追跡し、他のパラメータと競合しないようにする必要があるからです。
-
Cookie – クッキーは、Webサーバーが応答ヘッダーで送信し、ブラウザのクッキーに保存される小さな情報です。クライアントがさらにリクエストを行うと、クッキーがリクエストヘッダーに追加され、セッションを追跡するためにそれを利用できます。クッキーを使用してセッションを維持できますが、クライアントがクッキーを無効にした場合は機能しません。
- ほとんどの場合、セッションを追跡するだけでなく、将来のリクエストで使用できるデータをセッションに格納する必要があります。これを実装しようとすると多くの労力が必要です。
-
Javaでのセッション管理 – Cookie
Cookieは、Webアプリケーションで使用されることがよくあり、選択に基づいてレスポンスを個別に設定したり、セッションを追跡したりします。Servletセッション管理APIに進む前に、小さなWebアプリケーションを使用してCookieを使用してセッションを追跡する方法を示したいと思います。以下の画像のようなプロジェクト構造を持つ動的WebアプリケーションServletCookieExampleを作成します。
Webアプリケーションのデプロイメント記述子web.xmlは次のようになります:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://java.sun.com/xml/ns/javaee" xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>ServletCookieExample</display-name> <welcome-file-list> <welcome-file>login.html</welcome-file> </welcome-file-list> </web-app>
アプリケーションのウェルカムページはlogin.htmlであり、ここでユーザーから認証詳細を取得します。
<!DOCTYPE html> <html> <head> <meta charset="US-ASCII"> <title>ログインページ</title> </head> <body> <form action="LoginServlet" method="post"> ユーザー名:<input type="text" name="user"> <br> パスワード:<input type="password" name="pwd"> <br> <input type="submit" value="ログイン"> </form> </body> </html>
こちらがログインリクエストを処理するLoginServletです。
package com.journaldev.servlet.session; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class LoginServlet */ @WebServlet("/LoginServlet") public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; private final String userID = "Pankaj"; private final String password = "journaldev"; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // userIDとpasswordのリクエストパラメータを取得する String user = request.getParameter("user"); String pwd = request.getParameter("pwd"); if(userID.equals(user) && password.equals(pwd)){ Cookie loginCookie = new Cookie("user",user); // cookieの有効期限を30分に設定 loginCookie.setMaxAge(30*60); response.addCookie(loginCookie); response.sendRedirect("LoginSuccess.jsp"); }else{ RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html"); PrintWriter out= response.getWriter(); out.println("<font color=red>ユーザー名またはパスワードが間違っています。</font>"); rd.include(request, response); } } }
ここで、レスポンスに設定しているCookieとそれをLoginSuccess.jspに転送していることに注意してください。このCookieはセッションを追跡するためにそこで使用されます。また、Cookieのタイムアウトが30分に設定されていることにも注意してください。セッション追跡用のCookie値を設定するための複雑なロジックが理想的には必要です。これにより、他のリクエストと競合しないようにします。
<%@ page language="java" contentType="text/html; charset=US-ASCII" pageEncoding="US-ASCII"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> <title>ログイン成功ページ</title> </head> <body> <% String userName = null; Cookie[] cookies = request.getCookies(); if(cookies !=null){ for(Cookie cookie : cookies){ if(cookie.getName().equals("user")) userName = cookie.getValue(); } } if(userName == null) response.sendRedirect("login.html"); %> <h3>こんにちは、<%=userName %>さん、ログインに成功しました。</h3> <br> <form action="LogoutServlet" method="post"> <input type="submit" value="ログアウト" > </form> </body> </html>
直接JSPにアクセスしようとすると、ログインページにリダイレクトされます。ログアウトボタンをクリックすると、クライアントブラウザからCookieが削除されることを確認する必要があります。
package com.journal
-
Java Servletでのセッション – HttpSession
Servlet APIは、
HttpSession
インターフェースを介したセッション管理を提供します。次のメソッドを使用して、HttpServletRequestオブジェクトからセッションを取得できます。HttpSessionを使用すると、将来のリクエストで取得できる属性としてオブジェクトを設定できます。- HttpSession getSession() – このメソッドは常にHttpSessionオブジェクトを返します。リクエストにセッションが添付されている場合は、そのセッションオブジェクトを返します。セッションが添付されていない場合は、新しいセッションを作成して返します。
- HttpSession getSession(boolean flag) – このメソッドは、リクエストにセッションがある場合はHttpSessionオブジェクトを返し、それ以外の場合はnullを返します。
HttpSessionの重要なメソッドの一部は次のとおりです:
- String getId() – このセッションに割り当てられた一意の識別子を含む文字列を返します。
- Object getAttribute(String name) – このセッションに指定された名前でバインドされたオブジェクトを返します。名前の下にオブジェクトがバインドされていない場合はnullを返します。セッション属性を操作する他のメソッドには
getAttributeNames()
、removeAttribute(String name)
、setAttribute(String name, Object value)
があります。 - long getCreationTime() – このセッションが作成された時刻をミリ秒単位で返します。
getLastAccessedTime()
メソッドで最終アクセス時刻を取得できます。 - setMaxInactiveInterval(int interval) – サーブレットコンテナがこのセッションを無効にするまでのクライアントリクエスト間の時間(秒単位)を指定します。
getMaxInactiveInterval()
メソッドからセッションのタイムアウト値を取得できます。 - ServletContext getServletContext() – アプリケーションのServletContextオブジェクトを返します。
- boolean isNew() – クライアントがまだセッションについて知らない場合、またはクライアントがセッションに参加しない場合はtrueを返します。
- void invalidate() – このセッションを無効にし、それにバインドされているオブジェクトをアンバインドします。
JSESSIONIDクッキーの理解
HttpServletRequestのgetSession()メソッドを使用して新しいリクエストを作成すると、新しいHttpSessionオブジェクトが作成され、レスポンスオブジェクトに名前がJSESSIONIDで値がセッションIDのCookieが追加されます。このクッキーは、クライアントからの今後のリクエストでHttpSessionオブジェクトを識別するために使用されます。クライアント側でクッキーが無効になっていて、URLリライトを使用している場合、このメソッドは要求URLからjsessionidの値を使用して対応するセッションを見つけます。JSESSIONIDクッキーはセッショントラッキングに使用されるため、セッション関連の問題を回避するためにアプリケーションの目的に使用すべきではありません。HttpSessionオブジェクトを使用したセッション管理の例を見てみましょう。EclipseでServletコンテキストをServletHttpSessionExampleとして持つ動的Webプロジェクトを作成します。プロジェクトの構造は以下の画像のようになります。
login.htmlは以前の例と同じであり、アプリケーションのウェルカムページとしてweb.xmlで定義されています。LoginServletサーブレットはセッションを作成し、他のリソースや将来のリクエストで使用できる属性を設定します。
package com.journaldev.servlet.session;
import java.io.IOException;
import java.io.PrintWriter;import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;/**
* Servlet implementation class LoginServlet
*/
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private final -
Java Servletにおけるセッション管理 – URLリライト
前のセクションでHttpSessionを使用してセッションを管理できることを見ましたが、ブラウザでクッキーを無効にしている場合、動作しなくなります。これは、サーバーがクライアントからJSESSIONIDクッキーを受信しないためです。Servlet APIは、URLリライトをサポートしており、このような場合にセッションを管理するために使用できます。Servlet URLエンコーディングの良いところは、コーディングの観点から非常に使いやすく、URLをエンコードするという1つの手順だけが関与することです。Servlet URLエンコーディングのもう1つの良い点は、これがフォールバックアプローチであり、ブラウザのクッキーが無効になっている場合にのみ使用されることです。HttpServletResponse
encodeURL()
メソッドを使用してURLをエンコードでき、リクエストを別のリソースにリダイレクトしてセッション情報を提供する必要がある場合は、encodeRedirectURL()
メソッドを使用できます。私たちは、上記と同様のプロジェクトを作成しますが、ブラウザでクッキーが無効になっていてもセッション管理が正常に機能するように、URLリライトメソッドを使用します。EclipseのServletSessionURLRewritingプロジェクトの構造は、以下の画像のようになります。package com.journaldev.servlet.session; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * Servlet implementation class LoginServlet */ @WebServlet("/LoginServlet") public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; private final String userID = "admin"; private final String password = "password"; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // userIDおよびpasswordのリクエストパラメータを取得します。 String user = request.getParameter("user"); String pwd = request.getParameter("pwd"); if(userID.equals(user) && password.equals(pwd)){ HttpSession session = request.getSession(); session.setAttribute("user", "Pankaj"); // 30分後にセッションの有効期限を設定します。 session.setMaxInactiveInterval(30*60); Cookie userName = new Cookie("user", user); response.addCookie(userName); //エンコードされたURL文字列を取得します。 String encodedURL = response.encodeRedirectURL("LoginSuccess.jsp"); response.sendRedirect(encodedURL); }else{ RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html"); PrintWriter out= response.getWriter(); out.println("<font color=red>ユーザー名またはパスワードが間違っています。</font>"); rd.include(request, response); } } }
<%@ page language="java" contentType="text/html; charset=US-ASCII" pageEncoding="US-ASCII"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> <title>ログイン成功ページ</title> </head> <body> <% //セッションが存在する場合のみアクセスを許可します String user = null; if(session.getAttribute("user") == null){ response.sendRedirect("login.html"); }else user = (String) session.getAttribute("user"); String userName = null; String sessionID = null; Cookie[] cookies = request.getCookies(); if(cookies !=null){ for(Cookie cookie : cookies){ if(cookie.getName().equals("user")) userName = cookie.getValue(); if(cookie.getName().equals("JSESSIONID")) sessionID = cookie.getValue(); } }else{ sessionID = session.getId(); } %> <h3>こんにちは、<%=userName %>さん、ログインに成功しました。あなたのセッションIDは<%=sessionID %>です。</h3> <br> ユーザー=<%=user %> <br> <!-- セッション情報を渡したいすべてのURLをエンコードする必要があります --> <a href="<%=response.encodeURL("CheckoutPage.jsp") %>">チェックアウトページ</a> <form action="<%=response.encodeURL("LogoutServlet") %>" method="post"> <input type="submit" value="ログアウト" > </form> </body> </html>
<%@ page language="java" contentType="text/html; charset=US-ASCII"
pageEncoding="US-ASCII"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>ログイン成功ページ</title>
</head>
<body>
<%
String userName = null;
//セッションが存在する場合のみ
セッション管理API – セッション管理APIは、セッション追跡のための上記の方法をベースに構築されています。上記の方法の主な欠点は次のとおりです。
上記の方法はすべて完全ではなく、特定のシナリオではすべてが機能しません。そのため、これらのセッション追跡方法を利用してすべての場
これでJava Servletsのセッション管理に関する説明は終わりです。今後はServletフィルター、リスナー、およびクッキーについても説明します。更新:シリーズの次の記事をチェックしてください。Servletフィルター。