Cookieを削除するコードを題材に、Cookieごとの設定をどこへ置くかを考えます。例はHTTPSで動くアプリを想定し、セッションCookieは JSESSIONID、Pathは /、Domain属性は指定しません。
レビューで見た残念なコード
まず、期限切れのCookieを作るだけなら次の形で動きます。Cookieが増えるにつれて、これと同じクラスに別のCookieの生成や削除が加わる構成です。
import jakarta.servlet.http.Cookie;
public class CookieLogic {
public Cookie deleteJsessionCookie() {
Cookie cookie = new Cookie("JSESSIONID", "");
cookie.setPath("/");
cookie.setMaxAge(0);
cookie.setSecure(true);
cookie.setHttpOnly(true);
return cookie;
}
}CookieLogic logic = new CookieLogic();
response.addCookie(logic.deleteJsessionCookie());
何が残念か
Cookieごとに用途と有効期限が違います。全メソッドが同じ Cookie 型を返すと、セッションCookie専用の処理へ別のCookieを渡してもコンパイルで気付けません。
処方箋
設定を変更する理由が異なるCookieは、必要に応じて型や生成処理を分けます。呼び出し側はCookie名を文字列で繰り返し指定せず、用途に対応するファクトリを使います。
修正例
セッション用の型に名前と期限切れの設定をまとめます。ログアウトではサーバー側のセッションも無効化し、期限切れのCookieを応答に追加します。
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
public final class JSESSIONID extends Cookie {
private JSESSIONID() {
super("JSESSIONID", "");
setPath("/");
setSecure(true);
setHttpOnly(true);
setMaxAge(0);
}
public static JSESSIONID deleteCookie() {
return new JSESSIONID();
}
public static void logout(HttpServletRequest request, HttpServletResponse response) {
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
response.addCookie(deleteCookie());
}
}
既存のCookieを消すには、発行時の名前・Path・Domainと対応させます。Pathが /app の構成なら /app を使い、Domainを付けて発行する構成なら同じDomainを指定します。Secure を付けた例はHTTPSから返してください。
動作確認では、Cookieの期限と設定、既存セッションの無効化、セッションがないリクエストで新規発行しないことを確認します。既存のセキュリティ機構がログアウトを管理しているアプリでは、そのログアウト設定を使います。
