본 문서에서 다루는 내용은 다음과 같다.
쿠키와 세션?
동적
인 웹페이지에서 입력 정보를유지
할 필요가 있을 때 정보를 저장하는 장소에 따라 두 가지로 분류
- 웹 서버에 저장하는 경우:
세션
- 일정 시간동안 같은 사용자로부터 들어오는 일련의 요구를 하나의 상태로 보고 상태를 서버에 저장하며 유지 시킴
- 클라이언트에 저장하는 경우:
쿠키
- 서버에서 생성하고 클라이언트에서 관리하며 만료시간 여부에 따라 파괴됨
데이터가 작고 중요하지 않은 데이터는 클라이언트(쿠키) 쪽에서 관리하고 나머지는 웹서버(세션)에 저장하는 것이 일반적
다음과 같은 로그인 기능을 담당하는 기본적인 파일들이 본 프로젝트에 이미 구성되어 있다(소스코드 다운).
로그인 기능을 구현 후 로그인 상태를 유지
하는 방법은 크게 다음과 같이 두 가지가 존재
HttpSession
쿠키
컨트롤러에서 HttpSession
을 사용하려면 다음의 두 가지 방법중 한 가지를 사용
HttpSession 파라미터
를 사용
@PostMapping
public String form(LoginCommand loginCommand, Errors errors, HttpSession session){
... // session을 사용하는 코드
}
HttpServletRequest 파라미터
를 추가하고 HttpServletRequest를 이용해 HttpSession을 구함
@PostMapping
public String submit(
LoginCommand loginCommand, Errors errors, HttpServletRequest req){
HttpSession session = req.getSession();
... // session을 사용하는 코드
}
첫 번째 방법은 항상 HttpSession을 생성하지만, 두 번째 방법은
필요한
시점에만 HttpSession을 생성
두 방법 모두 기존에 존재하는 세션이 있을시, 존재하는 세션을 전달
담음
// LoginController.java
@Controller
@RequestMapping("/login")
public class LoginController {
...
@PostMapping
public String submit(
LoginCommand loginCommand, Errors errors, HttpSession session,
HttpServletResponse response) {
new LoginCommandValidator().validate(loginCommand, errors);
if (errors.hasErrors()) {
return "login/loginForm";
}
try {
AuthInfo authInfo = authService.authenticate(
loginCommand.getEmail(),
loginCommand.getPassword());
// 로그인에 성공 시 HttpSession의 authInfo 속성에 인증 정보 객체(authInfo)를 저장
session.setAttribute("authInfo", authInfo);
...
} catch (WrongIdPasswordException e) {
errors.reject("idPasswordNotMatching");
return "login/loginForm";
}
}
}
제거
함
// LogoutController.java
@Controller
public class LogoutController {
@RequestMapping("/logout")
public String logout(HttpSession session) {
session.invalidate();
return "redirect:/main";
}
}
비정상
적이며 이를 방지
해야 함리다이렉트
시키는 방법으로 해결할 수 있으나,모든
컨트롤러에 이런 세션 확인 코드를 삽입하는 것은 비효율
적
이렇게 다수의 컨트롤러에 대해
동일한 기능
을 적용해야 할 때 사용할 수 있는 것이HandlerInterceptor
org.springframework.web.HandlerInterceptor
인터페이스를 이용해 구현하며 다음과 같은 시점에 공통 기능
삽입 가능
매서드
를 정의
preHandle()
:실행하지 않음
postHandle()
:추가 기능
을 구현할 때 사용하며,afterCompletion()
:
뷰가 클라이언트에 응답을 전송한 뒤에 실행하며,
컨트롤러 실행 이후에 예기치 않게 발생한 익셉션 로그
나 실행 시간
을 기록하기에 적합
// AuthCheckInterceptor.java
public class AuthCheckInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
HttpSession session = request.getSession(false);
if (session != null) {
Object authInfo = session.getAttribute("authInfo");
if (authInfo != null) {
return true;
}
}
// 인증정보가 없어 실패 시, 다음과 같은 경로로 리다이렉트 시킴
response.sendRedirect(request.getContextPath() + "/login");
return false;
}
}
어디에 적용
할지 설정
이 다음과 같이 필요
// MvcConfig.java
@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
...
// 인터셉트를 정의하는 매서드
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authCheckInterceptor())
.addPathPatterns("/edit/**")
.excludePathPatterns("/edit/help/**");
}
...
}
Ant
경로 패턴을 이용하여 지정
Ant
경로 패턴?
Ant 패턴은 *, **, ?의 세 가지 특수 문자를 사용해 경로를 다음과 같이 표현
*
: 0개 또는 그 이상의 글자?
: 1개 글자**
: 0개 또는 그 이상의 폴더 경로
따라서 앞선 코드의 경우, http://localhost:8080/sp5-chap13/edit/changePassword 에 접근하면 로그인 폼으로리다이렉트
됨
쿠키
에 저장
하는 방식을 구현@CookieValue
어노테이션을 사용하는 것@CookieValue 어노테이션은 요청 매핑 어노테이션 적용 매서드의 Cookie 타입의 파라미터
에 적용
// LoginController.java
@Controller
@RequestMapping("/login")
public class LoginController {
...
@GetMapping
public String form(LoginCommand loginCommand,
/*
* 어노테이션을 통해 쿠키의 이름을 REMEMBER로 지정
* 지정한 이름의 쿠키가 없다면, required 속성 값을 false로 지정
* 만약 지정한 이름의 쿠키가 없는데, required가 ture면 익셉션 발생
*/
@CookieValue(value = "REMEMBER", required = false) Cookie rCookie) {
if (rCookie != null) {
loginCommand.setEmail(rCookie.getValue());
loginCommand.setRememberEmail(true);
}
return "login/loginForm";
}
/*
* 실제 쿠키를 생성하는 부분은 로그인을 처리하는 다음 매서드
* 쿠키를 사용하기 위해 HttpServletResponse 객체가 필요하므로 파라미터로 전달
*/
@PostMapping
public String submit(
LoginCommand loginCommand, Errors errors, HttpSession session,
HttpServletResponse response) {
...
// 쿠키를 추가하는 코드
Cookie rememberCookie =
new Cookie("REMEMBER", loginCommand.getEmail());
rememberCookie.setPath("/");
/*
* 로그인에 성공했을 때, 이메일 기억하기 체크박스 선택 여부에 따라
* 30일동안 유지되는 쿠키를 생성하거나
* 바로 삭제되는 쿠키를 생성
*/
if (loginCommand.isRememberEmail()) {
rememberCookie.setMaxAge(60 * 60 * 24 * 30);
} else {
rememberCookie.setMaxAge(0);
}
response.addCookie(rememberCookie);
...
}
}