스프링

P662

 

4.1.3 자동 로그인 구상하기

 

자동  로그인 처리의 기본 아이디어는  '세션 + 쿠키'를 이용하려 합니다. 보통은 HttpSession만을 이용하거나 쿠키만을 이용하지만, 이 두 가지를 섞어서 사용하는 예제입니다.  예제의 작성 이전에 코드로 작성해야 하는 상황에 대한 이해가 필요합니다.

 

쿠키와 세션으로 발생하는 상황은 아래의 네 가지 경우가 있을 수 있습니다.

 

  • HttpSession에 login 이름으로 보관된 객체가 없고, loginCookie 가 없는 경우

- 로그인과 관련된 아무런 정보가 없으므로, 사용자는 로그인이 필요한 상황입니다.

 

  •  HttpSession에 login 이름으로 보관된 객체가 있고, loginCookie가 없는 경우

- 세션에 login 이라는 이름으로 보관된 경우는 현재 사용자가 로그인한 상황이 확실합니다.

 

  • HttpSession 에 login 이름으로 보관된 객체가 없고, loginCookie가 존재하는 경우

- 사용자는 이전에 로그인을 한 적이 있을 수 있습니다. 사용자가 이전에 로그인을 할 때 loginCookie가 생성되었을 것이고,

어떤 이유로 인해 사용자는 브라우저를 종료했을 것입니다.

- 브라우저가 종료되면서, 세션 쿠키는 사라졌지만, loginCookie 는 5분 동안 보관되므로, loginCookie 가 있다는 것은 5분 사이에

접속한 적이 있다는 것을 의미합니다.

 

  • HttpSession 에 login 이름으로 보관된 객체가 있고, loginCookie가 있는 경우

- 사용자는 현재 접속 중인 사용자입니다.

 

 

의 경우 수 중에서 자동 로그인은 'HttpSession 에는 login 이름으로 보관된 객체가 없지만, loginCookie는 존재하는 상황입니다. 

이 경우 사용자는 이전에 로그인을 한 적이 있다는 것을 의미하므로, 과거 로그인 시점에 기록된 정보를 이용해서 다시 HttpSession에 login 이름

으로 UserVO 객체를 보관해 줘야 합니다.

 

이후의 모든 작업은 HttpSession에 login 이름으로 저장된 객체가 있으므로 , 모두 해됩니다.

 

 

4.2 자동 로그인의 구현

 

위의 설명을 요약하자면, '사용자가 loginCookie를 가지고 있다면, 그 값은 과거에 로그인한 시점에 세션 아이디'라는 것입니다.

 

이를 반대로 해석해보면 loginCookie에 있는 값을 이용해서 데이터베이스에서 UserVO의 정보를 읽어오고, 읽어온 UserVO 객체를 현재의

HttpSession에 보관하면 로그인이 된다는 것입니다. 이 과정은 다음과 같은 순서로 이뤄지게 됩니다.

 

  • 사용자가 로그인하면 데이터베이스에 현재 세션의 ID 값과 유효기관(7일) 을 기록합니다.
  • 사용자가 로그인하지 않은 상태에서 쿠키를 가지고 접속하면 쿠키의 내용물을 추출합니다.
  • 쿠키의 내용물로 데이터베이스를 조회해서 유효기간에 맞는 값인지 확인합니다.
  • 확인된 사용자는 세션에 로그인한 정보를 기록해서, 자동으로 로그인이 되도록 합니다.

 

4.2.1 데이터베이스의 변경

이를 위해서 가장 먼저 데이터베이스에 tbl_user 테이블 변경합니다.

테이블 변경

 


alter table tbl_user add COLUMN 

	sessionkey VARCHAR (50) not null default 'none';
	

alter table tbl_user add column sessionlimit timestamp;	

 

추가된 칼럼은 로그인하는 시점의 세션 아이디를 보관하는 sessionKey 칼럼과 sessionlimit 이름의 유효시간을 기록하는 칼럼입니다.

sessionlimit 칼럼의 경우 서버에서 다시 한 번 유효한 기간에 다시 접속을 했는지를 판단하기 위해서 작성해 주었습니다.

 

 

4.2.2 코드의 변경

사용자가 로그인을 하면 위의 칼럼들이 업데이트 돼야 하므로, 해당 SQL 을 작성해야 합니다.

 

 

4.2.2.1 UserDAO 의 변경

UserDAO에는 로그인한 사용자의 sessionKey와 sessionLimit를 업데이트하는 기능과, loginCookie에 기록된 값으로 사용자의 정보를 

조회하는 기능을 추가했습니다.

 

 

LoginDTO


public class LoginDTO {

  private String uid;
  private String upw;
  private boolean useCookie;

 ...이하 getter/setter, toString()

}

 

 

 

UserDAO

public interface UserDAO{
	
	public UserVO login(LoginDTO dto) throws Exception;
	
	public void keepLogin(String uid, String sessionId, Date next);
	
	public UserVO checkUserWithSessionKey(String value);
	
}

 

 

UserMapper.xml

	<update id="keepLogin">
		update tbl_user set sessionKey=#{sessionId}, sessionLimit=#{next} where uid=#{uid}
	</update>
	
	
	<select id="checkUserWithSessionKey" resultType="UserVO">
		select * from tbl_user where sessionKey =#{value} and sessionlimit > now()
	</select>

 

 

UserDAOImpl

	
	@Override
	public void keepLogin(String uid, String sessionId, Date next){
		
		Map<String, Object> paramMap =new HashMap<String, Object>();
		paramMap.put("uid", uid);
		paramMap.put("sessionId", sessionId);
		paramMap.put("next", next);
		session.update(namespace+".keepLogin", paramMap);
	}
	
	@Override
	public UserVO checkUserWithSessionKey(String value){
		
		return session.selectOne(namespace+".checkUserWithSessionKey", value);
	}
	

 

 

4.2.2.2 UserService 의 변경

 

UserService에는 아래와 같이 로그인 정보를 유지하는 keepLogin과 과거에 접속한 사용자인지를 확인하는 기능을 작성합니다.

 

UserService

public interface UserService{
	
	public UserVO login(LoginDTO dto) throws Exception;
	
	public void keepLogin(String uid, String sessionId, Date next ) throws Exception;
	
	public UserVO checkLoginBefore(String value);
	
	
}

 

UserServiceImpl

	@Override
	public void keepLogin(String uid, String sessionId, Date next) throws Exception{
		dao.keepLogin(uid, sessionId, next);
	}
	
	
	@Override
	public UserVO checkLoginBefore(String value){
		
		return dao.checkUserWithSessionKey(value);
	}
	

 

 

 

4.2.3 UserService 의 변경

 

UserService에는 아래와 같이 로그인 정보를 유지하는 keepLogin과 과거에 접속한 사용자인지를 확인하는 기능을 작성합니다.

 

UserService

public interface UserService {
	
	public UserVO login(LoginDTO dto) throws Exception;
	
	public void keepLogin(String uid, String sessionId, Date next) throws Exception;
	
	public UserVO checkLoginBefore(String value);
	
}

 

 

UserServiceImpl

	@Override
	public void keepLogin(String uid, String sessionId, Date next) 
			throws Exception{
		
		dao.keepLogin(uid, sessionId, next);
	}
	
	@Override
	public UserVO checkLoginBefore(String value){
		return dao.checkUserWithSessionKey(value);
	}

 

 

4.2.3 UserController 의 변경

UserController 는 사용자가 '자동 로그인' 을 선택한 경우 필요한 기능르 추가합니다.

 

	@RequestMapping(value="/loginPost", method=RequestMethod.POST)
	public void loginPOST(LoginDTO dto, HttpSession session, Model model) throws 
		Exception{
		
		UserVO vo =service.login(dto);
		
		if(vo==null){ return ;}
		
		model.addAttribute("userVO", vo);
		
		if(dto.isUseCookie()){
			int amount =60*60*24*7;
			
			Date sessionLimit =new Date(System.currentTimeMillis()+(1000*amount));
			
			service.keepLogin(vo.getUid(), seesion.getId(), sessionLimit);
		}
		
	}

 

코드이 핵심은 loginCookie 값이 유지되는 시간 정보를 데이터베이스에 저장하는 것입니다.

 

4.2.4 AuthInterceptor 의 변경

 

AuthInterceptor 에서는 현재 사용자의 세션에 login 이 존재하지 않지만, 쿠키 중에서 loginCookie 가 존재할 때 처리가 진행됩니다.

 

public class AuthInterceptor extends HandlerInterceptorAdapter{
	
	
	private static final Logger logger=LoggerFactory.getLogger(AuthInterceptor.class);
	
	@Inject
	private UserService service;
	
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		
		HttpSession session =request.getSession();
		
		if(session.getAttribute("login")==null){
			
			logger.info("current user is not logined");
			
			saveDest(request);
			
			Cookie loginCookie=WebUtils.getCookie(request, "loginCookie");
			
			if(loginCookie !=null){
				
				UserVO userVO =service.checkLoginBefore(loginCookie.getValue());
				
				logger.info("USERVO :" +userVO);
			
				if(userVO !=null){
					session.setAttribute("login", userVO);
					return true;
				}
			}
			
			response.sendRedirect("/user/login");
			return false;
		}
		
		return true;
	}
	
}

 

AuthInterceptor 는 UserService 타입의 객체를 주입받습니다.

현재 사용자가 HttpSession 에 적당한 값이 없는 경우 loginCookie 를 가지고 있는지를 체크합니다.

만일 과거에 보관한 쿠키가 있다면 UserService 객체를 이용해서 사용자의 정보가 존재하는지를 확인합니다. 만일 사용자의 정보가 존재한다면

HttpSession 에 다시 사용자의 정보를 넣어주게 됩니다.

 

4.2.5 자동 로그인 테스트

위의 코드가 정상적으로 동작하는지 알아보기 위해서는 다음과 같은 테스트가 진행돼야 합니다.

 

  • 로그인하지 않은 상용자가 로그인이 필요한 URI 에 접근하는 경우 : 로그인 페이지로 이동
  • 로그인할 'Remember Me'를 체크하지 않은 상태에서 로그인 실행, 이후 로그인 필요한 페이지로 이동 : 정상적인 이동
  • 브라우저를 종료하고, 2)번 테스트를 다시 진행 : HttpSession 이 변경됐으므로, 로그인 페이지로 이동
  • 로그인화면에서 'Remember Me'를 선택하고 로그인
  • 브라우저를 종료하고 다시 실행한 후 로그인이 필요한 URI 접속 : 정상적인 이동

 

게시물 등록의 경우 로그인이 필요한 URI 이므로 이 경로를 이용해서 테스트를 진행했을때 다음과 같이 결과가 처리됩니다.

 

 

 

 

 

 

 

 

 

 

spring

 

about author

PHRASE

Level 60  머나먼나라

황색의 치마는 아름다운 곤(坤)의 덕성을 대표하고 있는 것이다. 황색은 중도를 나타내는 색. 치마는 저고리의 아래에다 입는 옷으로 저고리에 따르는 것이다. 아내라면 남편에게, 신하라면 임금을 도와 화순하고 바르게 일하고 있는 모습이다. -역경

댓글 ( 4)

댓글 남기기

작성