세션과 쿠키

Session Cookie
사용자 데이터를 저장하는 역할
데이터를 서버에 저장
브라우저 단위로 생성되며,
브라우저가 종료되면 세션에 있는 데이터도 사라진다.
데이터를 사용자의 PC(로컬)에 저장
데이터의 유효기간 설정이 가능하여,
브라우저가 종료되더라도
유효기간 동안은 데이터를 계속 사용할 수 있다. 

 

UserController

1
2
3
4
5
6
7
8
9
10
11
12
13
@ResponseBody
@PostMapping("/signin")
public ModelAndView signinPost(ModelAndView mv, UserVO user) {   
  UserVO dbUser = userService.signin(user);      
  if(dbUser != null)
    mv.setViewName("redirect:/");
  else
    mv.setViewName("redirect:/signin");   
  
   mv.addObject("user", dbUser); //Interceptor(postHandler)에게 전송할 user 정보 
   return mv;
}
 
cs

 

 

LoginInterceptor

  • Servlet-context.xml에서 로그인 컨트롤러와 연결되어 있음
1
2
3
4
5
6
7
<beans:bean id="loginInterceptor" class="com.ysy.bakingdom.interceptor.LoginInterceptor" />
<interceptors>
  <interceptor>
    <mapping path="/signin"/>
    <beans:ref bean="loginInterceptor"/>
  </interceptor>
</interceptors>
cs


  • 로그인버튼을 클릭하고 컨트롤러에서 setViewName을 실행하기 직전에 작동하는 인터셉터(postHandle)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class LoginInterceptor extends HandlerInterceptorAdapter {
  @Autowired
  UserService userService;
  
  //로그인 완료 후 실행할 인터셉터
  @Override
  public void postHandle(
    HttpServletRequest request, HttpServletResponse response, Object handler, 
    ModelAndView modelAndView) throws Exception {
        
    //Controller의 mv에서 addObject로 "user"를 전달해 왔을 때 실행. 전달값이 없으면 null로 설정됨.   
    UserVO user = (UserVO)modelAndView.getModelMap().get("user");
    
    if(user != null) {
      //리퀘스트에 있는 세션 정보 가져오기
      HttpSession session = request.getSession();
      //세션에 user 정보 추가
      session.setAttribute("user", user);
            
      //자동로그인에 체크가 되어있으면       
      if(user.getUseCookie() != null) {
      // 여기서 getId는 SessionId를 의미한다.   
      Cookie autoLoginCookie = new Cookie("autoLoginCookie", session.getId());        
      // 쿠키를 찾을 경로    
      autoLoginCookie.setPath("/");         
      // 쿠키 유지 시간 ( sessionLimit)
      autoLoginCookie.setMaxAge(60*60*24*30); 
      response.addCookie(autoLoginCookie);
      Date user_sessionLimit = new Date(System.currentTimeMillis() + (amount * 1000L));
      userService.keepLogin(user.getUser_email(), session.getId(), user_sessionLimit);
      }            
    }
  }
}​​
 
cs
  • Controller에서 addObject로 담아보낸 user데이터를 받아옴.
  • user데이터가 있으면 (로그인이 가능하면), 세션에 user데이터를 담아 저장한다.

    === 자동로그인에 체크되어 있을 때 ==
  • useCookie 값이 null이 아니면 (로그인 할 때 자동로그인에 체크했으면)
    새로운 쿠키(autologincookie)를 생성하여 현재 세션에 저장되어 있는 세션아이디를 쿠키에 담는다.
  • 모든 URL범위에서 쿠키를 전송할 수 있도록 경로를 설정해준다. (setpath)
  • 저장된 쿠키의 유효기간을 설정해준다.
    - 30일동안 유효 : 60초 60분 24시간 * 30일 => 60*60*24*30
    - currentTimeMillis()는 long 타입으로 값을 반환한다. 여기에 60*60*24*30*1000을 연산하여 값을 보내주면 int값으로 계산되어 int타입을 벗어나 오버플로우가 발생한다. 따라서 1000L로 계산하여 연산 값을 long타입으로 만들어줘야한다. (int 범위 : –2,147,483,648 ~ 2,147,483,647 ,  60*60*24*30*1000 =2,592,000,000) 
  • response.addCookie에 쿠키데이터를 실어서 응답.
  • 아까 실려온 user데이터에서의 email과 세션데이터에 담겨져 있는 세션id, 그리고 오늘날짜로부터의 유효기간을 담아 Service에게 keepLogin을 시킨다.

 

  • UserService
1
void keepLogin(String user_email, String user_sessionId, Date user_sessionLimit);
cs

 

  • UserServiceImp
1
2
3
4
5
6
7
  @Override
  public void keepLogin(String user_email, String user_sessionId, Date user_sessionLimit) {
    if(user_email == null || user_sessionId == null || user_sessionLimit == null
      return;
    userDao.keepLogin(user_email, user_sessionId, user_sessionLimit);  
  }
 
cs

 

  • UserDAO
1
void keepLogin(@Param("user_email"String user_email, @Param("user_sessionId"String user_sessionId, @Param("user_sessionLimit") Date user_sessionLimit);
cs

 

  • UserMapper
1
2
3
4
5
6
  <update id="keepLogin">
    update user set
      user_sessionId = #{user_sessionId},
      user_sessionLimit = #{user_sessionLimit}
    where user_email = #{user_email}
  </update>
cs

 

 

AutoLoginInterceptor

  • servlet-context.xml에서 모든 url 경로와 연결되어 있다. = 모든 페이지변경마다 AutoLoginInterceptor가 작동된다. 
<interceptors>
    <interceptor>
        <mapping path="/signin"/>
        <beans:ref bean="loginInterceptor"/>
    </interceptor>
    <interceptor>
        <mapping path="/**/"/>
        <beans:ref bean="autoLoginInterceptor"/>
    </interceptor>
</interceptors>
cs

 

  • url 경로를 따라 컨트롤러로 진입하기 직전에 작동되는 인터셉터(preHandle)
public class AutoLoginInterceptor extends HandlerInterceptorAdapter {
  
  @Autowired
  UserService userService;
  // url이동시 컨트롤러에 진입하기 전에 실행되는 인터셉터
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 
                            throws Exception {   
    // 현재 세션 데이터를 가져온다.
    HttpSession session = request.getSession();
    // 세션에 담겨진 user정보를 VO타입으로 담는다.
    UserVO user = (UserVO)session.getAttribute("user");   
    // 만약 세션에 담겨진 user정보가 없으면, 
    if(user == null) {
      Cookie autoLoginCookie = WebUtils.getCookie(request, "autoLoginCookie");  
      if(autoLoginCookie!=null) {
        user = userService.getUserByCookie(autoLoginCookie.getValue());
        if(user != null) {
          session.setAttribute("user", user);
        }
      }
    }    
    return true;
  }
}
cs
  • 세션에 "user"로 전달 받은 유저 데이터를 가져와 VO타입 user에 저장한다.
  • 만약 세션에 담겨진 "user" 정보가 없으면
    (= 로그인되지 않은 상태 or 세션유효기간이 만료되어 자동로그인이 종료된 상태 or 자동로그인이 아닌 상태)
    해당 user의 로그인 관련 쿠키 상태를 확인하기 위해, request에서 "autoLoginCookie"를 가져온다.
  • 가져올 autoLoginCookie 정보가 없으면 (autoLoginCookie==null) 인터셉터 작동 종료.
  • 가져올 autoLoginCookie가 있으면, 해당 Cookie 값(세션아이디)을 가지는 유저 데이터를 찾아 VO user에 저장한다. 유저 데이터가 정상적으로 존재하면 세션 정보를 user로 설정한다.
  • 위 내용을 매 페이지마다(경로 변경마다) 작동하며 로그인을 유지시킨다.

 

  • UserService
UserVO getUserByCookie(String user_sessionId);
cs

 

  • UserServiceImp
@Override
public UserVO getUserByCookie(String user_sessionId) {
  return userDao.getUserByCookie(user_sessionId);
}
cs

 

  • UserDAO
UserVO getUserByCookie(String user_sessionId);
cs

 

  • UserMapper
<select id="getUserByCookie" resultType="com.ysy.bakingdom.vo.UserVO">
  select * from user where user_sessionId = #{user_sessionId} and user_sessionLimit > now()
</select>
cs
  • user_sessionLimit이 현재 시간보다 클 경우 (유효기간이 남아있을 경우)에만 검색된다.