Cookie idCookie = new Cookie("memberId", String.valueOf(loginMember.getId()));
response.addCookie(idCookie);
@GetMapping("/")
public String homeLogin(@CookieValue(name="memberId", required = false) Long memberId, Model model) {..
위 경우는 정상 로그인이 된다면 / 화면으로 돌아가는것
여기서 required = false는 최초 로그인하지 않는 경우(쿠키값이 없는경우)도 있기 때문에 false로 한다.
Cookie cookie = new Cookie("memberId", null);
cookie.setMaxAge(0);
response.addCookie(cookie);
당연히 중요정보를 쿠키를 사용하면 절대 절대 안된다!
- 회원과 관련된 정보는 전혀 클라이언트에 전달하지 않는다는 것
- 오직 추정 불가능한 세션 ID만 쿠키를 통해 클라이언트에 전달
@Component
public class SessionManager {
private Map<String, Object> sessionStore = new ConcurrentHashMap<>();
public static final String SESSION_COOKIE_NAME = "mySessionId";
/**
* 세션 셜정
* * SessionId 생성 (임의의 추정 불가능한 랜덤 값)
* * 세션 저장소에 sessionId와 보관할 값 저장
* * sessionId로 응답 쿠키를 생성해서 클라이언트에 전달
*/
public void createSession(Object value, HttpServletResponse response) {
// 세션 id를 생성하고 값을 세션에 저장
String sessionId = UUID.randomUUID().toString();
sessionStore.put(sessionId, value);
// Cookie 생성
Cookie mySessionCookie = new Cookie(SESSION_COOKIE_NAME, sessionId);
response.addCookie(mySessionCookie);
}
/**
* 세션 조회
*/
public Object getSession(HttpServletRequest request) {
Cookie sessionCookie = findCookie(request);
if(sessionCookie==null) {
return null;
}
return sessionStore.get(sessionCookie.getValue());
}
/**
* 세션 만료
*/
public void expire(HttpServletRequest request) {
Cookie sessionCookie = findCookie(request);
if(sessionCookie!=null) {
sessionStore.remove(sessionCookie.getValue());
}
}
public Cookie findCookie(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if(cookies==null) return null;
return Arrays.stream(cookies)
.filter(c -> c.getName().equals(SESSION_COOKIE_NAME))
.findFirst()
.orElse(null);
}
}
class SessionManagerTest {
SessionManager sessionManager = new SessionManager();
@Test
void sessionTest() {
//세션생성
Member member = new Member();
MockHttpServletResponse response = new MockHttpServletResponse();
sessionManager.createSession(member, response);
// 요청에 응답 쿠키 저장
MockHttpServletRequest request = new MockHttpServletRequest();
request.setCookies(response.getCookies());
// 세션조회
Object result = sessionManager.getSession(request);
Assertions.assertThat(result).isEqualTo(member);
// 세션만료
sessionManager.expire(request);
Assertions.assertThat(sessionManager.getSession(request)).isNull();
}
}
-> HttpRequestServlet, HttpResponseServlet은 인터페이스가 아니기 때문에 테스트하려면 Mock(가짜객체)를 사용한다.
// 로그인 성공 처리 TODO
// 세션이 있으면 있는 세션 반환, 없으면 신규 세션을 생성
HttpSession session = request.getSession();
// 세션에 로그인 회원 정보 보관
session.setAttribute(SessionConst.LOGIN_MEMEBER, loginMember);
// false로 해야 세션이 없을때 자동으로 생성하지 않는다.
HttpSession session = request.getSession(false);
if(session!=null) {
// 세션초기화
session.invalidate();
}
@GetMapping("/")
public String homeLoginV3(@SessionAttribute(name=SessionConst.LOGIN_MEMEBER, required = false) Member member, Model model) {
// 세션에 회원 정보가 없다면 기본 홈
if(member==null) {
return "home";
}
//로그인
model.addAttribute("member", member);
return "loginHome";
}
@SessionAttribute(name=SessionConst.LOGIN_MEMEBER, required = false) 라는 Argument로 세션의 이름과 require(여기서는 메인화면이기 때문에 세션이 없는 경우가 있어서 false)로 세션정보를 바로 받아올 수 있다.
참고로 로그인을 처음 시도하면 URL이 다음과 같이 jsessionid를 포함하고 있는 것을 확인할 수 있다.
따라서 application.properties에 아래 세팅값을 추가한다.
server.servlet.session.tracking-modes=cookie : 쿠키로 트래킹 모드
server.servlet.session.timeout=1800 : 세션유지시간