Session

- サーバーに重要な情報を保管し、接続を維持する方法である。
- 前のCookieの解決を解決するためには、重要な情報はすべてサーバに保存し、クライアントとサーバは **Session ID（推定不可能な任意の識別子値、UUID 等使用）** にて接続しなければならない。 この方法をSessionという。
```java
@PostMapping("/login")
public String login(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult, HttpServletResponse response) {
    if (bindingResult.hasErrors()) {
        return "login/loginForm";
    }

    // 1. ユーザーがログイン情報(Login Form)を伝達すれば、サーバーで該当ユーザーであるか確認する。
    Member loginMember = loginService.login(form.getLoginId(), form.getPassword());

    if (loginMember == null) {
        bindingResult.reject("loginFail", "Dまたはパスワードが正しくありません。");
        return "login/loginForm";
    }

    sessionManager.createSession(loginMember, response);

    return "redirect:/";

}
```
```java
@Component
public class SessionManager {

    public static final String SESSION_COOKIE_NAME = "mySessionId";
    // String : sessionId , Object : 値
    private Map<String, Object> sessionStore = new ConcurrentHashMap<>();

    // Session 生成
    public void createSesssion(Object value, HttpServletResponse response) {

        // 2.ユーザが正しければ、UUIDで推定できないsessionIdを作る。
        String sessionId = UUID.randomUUID().toString();
        // 3. sessionStoreを作り
        // セッションIDと値(login Member)を保存する。
        sessionStore.put(sessionId, value);

        // 4. サーバはsessionIdのみをCookeに入れてクライアントに渡す。
        Cookie mySessionCookie = new Cookie(SESSION_COOKIE_NAME, sessionId);
        response.addCookie(mySessionCookie);
    }
}
```

5.クライアントはCookieストレージにCookieを保管し、要求のたびにsessionIdを配信する。
- クライアントとサーバは結Cookieを介して接続するが、推定不可能なsessionIdのみを入れて配信し、会員情報のような重要な情報は配信しない。

6.その後、サーバーはクライアントが伝達したsessionIdでsessionStoreに保管しておいたSession情報を照会する。
- 長所
    - sessionIdがハッキングされても、ここには重要な情報がない。
    - sessionの満了時間を短く（ex。30分）設定すれば、sessionIdを盗んでも時間が経てば使用できなくなり、ハッキングが疑われる場合、サーバーから該当Session強制的に除去すれば良い。
```java
@GetMapping("/")
public String homeLogin(HttpServletRequest request, Model model) {

    // クライアントが伝達したsessionIdで
    // sessionStoreに保管しておいたSession情報を照会する。
    Member member = (Member)sessionManager.getSession(request);

    //로그인
    if (member == null) {
        return "home";
    }

    model.addAttribute("member", member);
    return "loginHome";
}
```
```java
@Component
public class SessionManager {

    // Sesssion 照会
    public Object getSession(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        if (cookies == null) {
            return null;
        }

        for (Cookie cookie : cookies) {
            if (cookie.getName().equals(SESSION_COOKIE_NAME)) {
                return sessionStore.get(cookie.getValue());
            }
        }
        return null;
    }
}
```
7.ログアウトするときは、sessionStoreにある値を削除すればよいが、Servletが提供するHttpSession(以後、別途ポスト作成)を使用すれば、invalidateメソッドを使用すればよい。
```java
@PostMapping("/logout")
public String logout(HttpServletRequest request) {
    sessionManager.expire(request);
    return "redirect:/";
}
```
```java
@Component
public class SessionManager {

    // Session 満了
    public void expire(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals(SESSION_COOKIE_NAME)) {
                    sessionStore.remove(cookie.getValue());
                }
            }
        }
    }
}
```