| この記事の要点 |
|
セッションとは
HTTP はリクエストごとに独立しているため、そのままでは「誰からのアクセスか」が分かりません。サーバーがセッション ID を Cookie(JSESSIONID)で渡し、その ID に紐づく保管場所を用意する仕組みがセッションです。
1 回目のアクセス ブラウザ → サーバー
サーバー: セッションを作り Set-Cookie: JSESSIONID=ABC123
2 回目以降 ブラウザ: Cookie: JSESSIONID=ABC123
サーバー: ABC123 の保管場所を取り出す
基本操作
@WebServlet("/mypage")
public class MyPageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
HttpSession session = request.getSession(); // 無ければ作る
// HttpSession s2 = request.getSession(false); // 無ければ null
// 保存
session.setAttribute("userId", 42);
session.setAttribute("user", new User(42, "田中"));
// 取得(Object で返るのでキャストする)
Integer userId = (Integer) session.getAttribute("userId");
User user = (User) session.getAttribute("user");
// 削除
session.removeAttribute("userId");
// 情報
System.out.println(session.getId());
System.out.println(session.isNew());
System.out.println(session.getCreationTime());
System.out.println(session.getLastAccessedTime());
}
}
getSession(false) は「あれば返す、無ければ null」です。ログイン判定のように「作りたくない」場面ではこちらを使ってください。引数なしで呼ぶと、未ログインの訪問者にもセッションが作られ、メモリを消費します。
取り出しは null とキャストに注意
HttpSession session = request.getSession(false);
if (session == null) {
response.sendRedirect("/login");
return;
}
Object raw = session.getAttribute("userId");
if (raw == null) {
response.sendRedirect("/login");
return;
}
// 型が違うと ClassCastException
if (!(raw instanceof Integer userId)) {
session.invalidate();
response.sendRedirect("/login");
return;
}
// ヘルパーを用意しておくと安全
private static <T> Optional<T> attr(HttpSession s, String key, Class<T> type) {
if (s == null) return Optional.empty();
Object v = s.getAttribute(key);
return type.isInstance(v) ? Optional.of(type.cast(v)) : Optional.empty();
}
ログイン処理
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException {
User user = authenticate(request.getParameter("id"),
request.getParameter("password"));
if (user == null) {
request.setAttribute("error", "IDまたはパスワードが違います");
return;
}
// 1. セッション ID を作り直す(セッション固定化攻撃への対策)
request.changeSessionId();
// 2. 必要な情報だけ保存する
HttpSession session = request.getSession();
session.setAttribute("userId", user.getId());
session.setMaxInactiveInterval(30 * 60); // 30 分無操作で失効
response.sendRedirect("/mypage");
}
changeSessionId() を呼ばないと、攻撃者があらかじめ用意した ID のままログインが成立します。その ID を知っている攻撃者は、そのままログイン済みの状態を使えてしまいます(セッション固定化)。Servlet 3.1 以降で使えます。
ログアウト
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate(); // セッションを破棄する
}
// session.getAttribute("x"); // IllegalStateException: 破棄後は触れない
// Cookie も消したいとき
Cookie cookie = new Cookie("JSESSIONID", "");
cookie.setMaxAge(0);
cookie.setPath(request.getContextPath() + "/");
response.addCookie(cookie);
response.sendRedirect("/login");
有効期限
session.setMaxInactiveInterval(1800); // 秒。この時間アクセスが無ければ失効
session.setMaxInactiveInterval(-1); // 無期限(推奨しない)
System.out.println(session.getMaxInactiveInterval());
<!-- web.xml で既定値を決める(分単位) -->
<session-config>
<session-timeout>30</session-timeout>
<cookie-config>
<http-only>true</http-only>
<secure>true</secure>
<same-site>Lax</same-site>
</cookie-config>
</session-config>
| Cookie 属性 | 意味 | 推奨 |
|---|---|---|
HttpOnly | JavaScript から読めなくする | 必ず有効(XSS でセッションを盗まれない) |
Secure | HTTPS のときだけ送る | 本番では有効 |
SameSite | 他サイト由来のリクエストで送るか | Lax。決済系は Strict |
Spring MVC での書き方
@Controller
public class MyPageController {
// HttpSession をそのまま受け取れる
@GetMapping("/mypage")
public String mypage(HttpSession session, Model model) {
Object userId = session.getAttribute("userId");
if (userId == null) return "redirect:/login";
model.addAttribute("userId", userId);
return "mypage";
}
}
// セッションに載せるモデル属性を宣言する
@Controller
@SessionAttributes("cart")
public class CartController {
@ModelAttribute("cart")
public Cart cart() { return new Cart(); }
@PostMapping("/cart/clear")
public String clear(SessionStatus status) {
status.setComplete(); // @SessionAttributes の分だけ破棄する
return "redirect:/cart";
}
}
実際の認証には Spring Security を使うのが標準です。セッション固定化対策やタイムアウト、同時ログイン数の制御が設定だけで有効になります。
何を入れて何を入れないか
| 入れてよい | 入れない |
|---|---|
| ユーザー ID・権限などの小さな値 | パスワード・カード番号 |
| 画面の入力途中の状態(ウィザード) | 検索結果の全件(数 MB になる) |
| CSRF トークン | DB から取れる情報の丸ごとコピー |
| 直列化できるオブジェクト | Connection や InputStream などの資源 |
セッションは利用者ごとにサーバーのメモリを消費します。同時 1,000 人で 1 人 1MB を持てば 1GB です。大きなデータは ID だけ保存し、必要なときに取り直してください。
複数台構成での注意
// Spring Session + Redis を使うと、サーバーをまたいで共有できる
// build.gradle:
// implementation 'org.springframework.session:spring-session-data-redis'
// application.properties:
// spring.session.store-type=redis
// spring.session.timeout=30m
既定のセッションはそのサーバーのメモリ上にあります。ロードバランサで振り分けると、別のサーバーに届いた時点でログイン状態が消えます。対処は次のいずれかです。
- 外部ストアに置く(Redis / DB)— 台数を増やしても影響がなく、再起動でも消えない
- 同じ利用者を同じサーバーへ送る(スティッキーセッション)— 簡単だが偏りやすく、再起動で失う
- セッションを使わず JWT などトークンで持つ — 失効の扱いが別途必要になる
セッションに入れるクラスは直列化できるようにする
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private String name;
private transient Connection conn; // 保存しないものは transient
}
Tomcat は再起動時にセッションをファイルへ書き出します(セッションの永続化)。Serializable でないオブジェクトが入っていると NotSerializableException が出て、セッションが失われます。
関連
子ページ
子ページはありません
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- djangoのテンプレートの作成とヘッダー・フッターの共通化 2026-10-03 21:41:49
- テンプレートフラグメント(ヘッダー等の共有化) 2026-10-03 21:41:49
- reCAPTCHA v3 使い方(サンプル付き) 2026-10-03 21:37:05
- Content-Type一覧|MIMEタイプとはとHTTPでの主な使用場面 2026-10-03 21:37:05
- SpringにおけるAOPの使い方 2026-10-03 21:37:05
- X (Twitter) API でツイートできないがエラーが出ない問題の原因と対処 2026-10-03 11:33:01
- X (Twitter) API アプリケーション登録完全ガイド|v2・Bearer Token・OAuth 2.0 PKCE 2026-10-03 11:33:01
- X (Twitter) API 完全ガイド|従量課金の料金・単価(2026年10月)と v2 移行 2026-10-03 11:32:40
- Google DeepMind とは?Gemini・AlphaFold の開発元 2026-10-03 11:26:56
- Cursor とは?AI 統合型コードエディタの使い方・料金 2026-10-03 11:26:56
- Claude (Anthropic) とは?AIチャットの使い方・モデルファミリ・API 2026-10-03 11:26:56
- AIベンダー一覧:OpenAI・Anthropic・Google DeepMind・Microsoft・Meta 2026-10-03 11:26:56
- クラウド・インフラ完全ガイド — AWS/Azure/GCP/Kubernetes 2026-10-03 11:26:56
- テキストエディタ完全比較 (VS Code / Cursor / Vim / Emacs / IDE) 2026-10-03 11:26:56
- プログラミング学習プラットフォーム|Scratch・micro:bit ほか 2026-10-03 11:26:56