본문 바로가기

JAVA/Spring

Spring Interceptor HttpSession Login

반응형

Spring Interceptor HttpSession Login(스프링 인터셉터 HttpSession으로 로그인 처리)


HttpSession을 이용하는 로그인처리
웹에서 로그인의 가장 기본적인 방식은 HttpSession 객체를 이용해서 사용자의 정보를 보관하고, 피룡한 경우 사용하거나 수정하는 방식

HttpSession의 동작은 실제로 세션 쿠키(session cookie)를 통해서 이뤄지는데, 서버는 필요한 경우 접속한 브라우저에 공유한 세션 쿠키를 전달하고, 매번 브라우저에서 서버를 호출 할 때 세션 쿠키를 같이 가지고 다니기 때문에 이를 마치 열쇠처럼 사용해서 필요한 데이터를 보관한다.
세션 쿠키가 열쇠(key)라면 HttpSession은 열쇠가 필요한 잠금장치가 되어 있는 상자와 유사하다. 이 상자들을 모여있는 공간을 '세션 공간Session Repository'라고 하는데, 너무나 많은 세션이 존재하면 서버의 성능에 영향을 미치기 때문에 서버에는 일정시간 이상 사용되지 않는 상자들을 정리하는 기능이 있다. (web.xml 을 이용해서 HttpSession의 timeout을 지정할 수 있다)

세션을 이용하는 방식의 핵심은 HttpSession을 이용해서 원하는 객체를 보관할 수 있다는 점이다. 사용자는 항상 열쇠에 해당하는 세션 쿠키를 가지고 접근하고, 서버의 내부 상자에 필요한 객체를 보관하기 때문에 안전하다는 장점이 있다.
세션에 보관된 객체는 JSP에서 EL을 이용해서 자동으로 추적하는 방식을 사용한다.
예를들어 ${name} 은 page -> request -> session -> application의 순서대로 원하는 데이터를 검색한다.
이와 같은 방식으로 동작하기 때문에 JSP를 개발하는 개발자는 자신이 사용하는 변수가 request에 존재하는 것인지, 세션에 존재하는 것인지에 대해서 고민하지 않아도 된다.


컨트롤러에서 HttpSession 객체를 처리할것인가? 인터셉터에서 HttpSession을 처리할것인가?
스프링 MVC는 컨트롤러에서 필요한 모든 자원을 파라미터에서 수집해서 처리하기 때문에 HttpServletRequest나 HttpSession과 같은 자원들 역시 파라미터로 처리해도 아무런 문제가 없다.

@Controller

@RequestMapping("/user")

public class UserController {

@Inject

private UserService service;


@RequestMapping(value="/login", method=RequestMethod.GET)

public void loginGET(@ModelAttribute("dto") LoginDTO dto) {


}


@RequestMapping(value="/loginPost", method=RequestMethod.POST)

public void loginiPOST(LoginDTO dto, HttpSession session, Model model) throws Exception {

UserVO vo = service.login(dto);


if(vo == null) {

return;

}


model.addAttribute("userVO",vo);

}

}


LoginInterceptor

public class LoginInterceptor extends HandlerInterceptorAdapter {

private static final string LOGIN = "login";

private static final Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);


@Override

public void postHandler(HttpServletRequest request,

HttpServletResponse reponse, Object handler, ModelAndView modelAndView ) throws Exception {


HttpSession session = request.getSession();


ModelMap modelMap = modelAndView.getModelMap();

Object userVO = modelMap.get("userVO");


if(userVO != null){


logger.info("new login success");

session.setAttribute(LOGIN, userVO);

response.sendRedirect("/");

}

}


public boolean preHandler(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {


HttpSession session = request.getSession();


if(session.getAttribute(LOGIN) != null) {

logger.info("clear login data before");

session.removeAttribute(LOGIN);

}


return ture;

}

}

LoginInterceptor는 '/loginPost'로 접근하도록 설정하는 것을 목적으로 작성한다.
preHandler()에서는 기존 HttpSession에 남아 있는 정보가 있는 경우에는 정보를 삭제한다.
postHandler()에서는 UserController에서 'userVO'라는 이름으로 객체를 담아둔 상태이므로, 이 상태를 체크해서 HttpSession에 저장한다.


LoginInterceptor의 설정은 '/loginPost' 의 동작에서 이뤄져야 하므로 servlet-context.xml 설정

<beans:bean id="loginInterceptor" class="org.zerock.interceptor.LoginInterceptor"></beans:bean>

<interceptors>

<interceptor>

<mapping path="/user/loginPost" />

<beans:ref bean="loginInterceptor" />

</interceptor>

</interceptors>


AuthInterceptor

 public class AuthInterceptor extends HandlerInterceptorAdapter {

private static final Logger logger = LoggerFactory.getLogger(AuthInterceptor.class);

@Override

public boolean preHandler(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {


HttpSession session = request.getSession();l


if(session.getAttribute("login") == null) {

logger.info("current user is not logined");


resoponse.sendRedirect("/user/login");

return false;

}

return ture;

}

}

LoingInterceptor가 로그인한 사용자에 대해서 postHandle()을 이용해서 HttpSession 에 보관하는 처리를 담당한다면,
AuthInterceptor는 특정 경로에 접근하는 현재 사용자의 로그인한 상태의 사용자인지를 체크하는 역할을 처리한다.
AuthInterceptor는 preHandler()을 이용해서 현재 사용자가 로그인한 상태인지를 체크 하고 컨트롤러를 호출하게 할것인지를 결정한다.
만일 사용자가 로그인하지 않는 상태라면 로그인하는 '/user/login'으로 이동한다.

AuthInterceptor servlet-context.xml 설정

<beans:bean id="loginInterceptor" class="org.zerock.interceptor.LoginInterceptor"></beans:bean>

<beans:bean id="authInterceptor" class="org.zerock.interceptor.AuthInterceptor"></beans:bean>

<interceptors>

<interceptor>

<mapping path="/user/loginPost" />

<beans:ref bean="loginInterceptor" />

</interceptor>

<interceptor>

<mapping path="/sboard/register" />

<beans:ref bean="authInterceptor" />

</interceptor>

</interceptors>


자동 페이지의 이동처리

게시물작성 페이지(로그인 필요) -> 로그인 페이지 -> 성공후 '/'경로로 이동
사용자가 원하는 URI가 무엇이었는지 보관했다가 로그인 성공 후 해당 경로로 이동시켜주는 것


AuthInterceptor 변경

public class AuthInterceptor extends HandlerInterceptorAdapter {

private static final Logger logger = LoggerFactory.getLogger(AuthInterceptor.class);



private void saveDest(HttpServletRequest req) {

String uri = req.getRequestURI();


String query = req.getQueryString();


if(query == null || query.equals("null")) {

query = "";

}else {

query = "?"+query;

}


if(req.getMethod().equals("GET")) {

logger.info("dest: "+ (uri+query));

req.getSession().setAttribute("dest", uri+query);

}

}


@Override

public boolean preHandler(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {


HttpSession session = request.getSession();l


if(session.getAttribute("login") == null) {

logger.info("current user is not logined");


saveDest(request);


resoponse.sendRedirect("/user/login");

return false;

}

return true;

}


AuthInterceptor는 saveDest() 메소드를 이용해서 원래 사용자가 원하는 페이지의 정보는 HttpSession에 'dest'라는 이름으로 저장한다.
GET 방식인 경우에 URI 정보 뒤의 파라미터들을 함께 보관해야 한다.

LoingInterceptor 변경

  @Override

public void postHandler(HttpServletRequest reqest, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 


HttpSession session = request.getSession();


ModelMap  modelmap = modelAndView.getModelMap();

Object userVO = modelMap.get("userVO");


if(userVO != null) {

logger.info("new login success");

session.setAttribute(LOGIN, userVO);


Object dest = session.getAttribute("dest");

response.sendRedirect(dest != null ? (String)dest : "/");

}

}

}

LoingInterceptor는 로그인 성공 후 response.sendRedirect() 작업에 'dest'정보를 사용하여 URI로 리다이렉트 시킨다.


게시물작성 페이지(로그인 필요) -> 로그인 페이지 -> 성공후 게시물 작성 페이지로 이동



반응형

'JAVA > Spring' 카테고리의 다른 글

MyBatis Mapper  (0) 2017.12.18
Spring login with cookie  (0) 2017.12.14
Spring Interceptor  (0) 2017.12.13
Spring Transaction  (0) 2017.11.27
Spring AOP  (0) 2017.11.21