3 분 소요

1. 로그인 처리를 위한 코드 준비

이 페이지에서는 세션에 관한 내용을 설명한다. 로그인 기능을 이용해서 이 내용을 설명할 것이므로 로그인과 관련된 몇 가지 필요한 코드를 작성한다.
먼저 로그인 성공 후 인증 상태 정보를 세션에 보관할 때 사용할 AuthInfo 클래스를 다음과 같이 작성한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class AuthInfo {
    private Long id;
    private String email;
    private String name;

    public AuthInfo(Long id, String email, String name) {
        this.id = id;
        this.email = email
        this.name = name;
    }

    public Long getId() {
        return id;
    }
    
    public String getEmail() {
        return email;
    }

    public String getName() {
        return name;
    }
}

이메일과 비밀번호가 일치하는지 확인해서 AuthInfo 객체를 생성하는 AuthService 클래스는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class AuthService {
    private MemberDao memberDao;

    public void setMemberDao(MemberDao memberDao) {
        this.memberDao = memberDao;
    }

    public AuthInfo authenticate(Stirng email, Stirng password) {
        Member member = memberDao.selectByEmail(email);
        if(member == null) {
            throw new WrongIdPasswordException();
        }
        if(!member.mathPassword(password)){
            throw new WrongIdPasswordException();
        }
        return new AuthInfo(member.getId(),
                member.getEmail(),
                member.getName());
    }
}

이제 AuthService를 이용해서 로그인 요청을 처리하는 LoginController 클래스는 다음과 같다.

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
@Controller
@RequestMapping("/login")
public class LoginController {
    private AuthService authService;

    public void setAuthService(AuthService authService) {
        this.authService = authService;
    }

    @GetMapping
    public String form(LoginCommand loginCommand) {
        return "login/loginForm"
    }

    @PostMapping
    public String submit(LoginCommand loginCommand, Errors errors) {
        new LoginCommandValidator().validate(loginCommand, errors);
        if(errors.hasErrors(){
            return "login/loginForm";
        })
        try{
            AuthInfo authInfo = authService.authenticate(
                    loginCommand.getEmail(),
                    loginCommand.getPassword());
            
            //TODO 세션에 authInfo 저장해야 함
            return "login/loginSuccess";
        }catch(WrongIdPasswordException e)  {
            errors.reject("idPasswordNotMatching");
            return "login/loginForm";
        }
    }
}

몇몇 class나 jsp는 생략했다.

2. 컨트롤러에서 HttpSession 사용하기

로그인 기능을 구현했는데 한 가지 빠진 것이 있다. 그것은 바로 로그인 상태를 유지하는 것이다. 로그인 상태를 유지하는 방법은 크게 HttpSession을 이용하는 방법과 쿠키를 이용하는 방법이 있다.
외부 데이터베이스에 세션 데이터를 보관하는 방법도 사용하는데 큰 틀에서 보면 HttpSession과 쿠키의 두 가지 방법으로 나뉜다.

컨트롤러에서 HttpSession을 사용하려면 다음의 두 가지 방법 중 한 가지를 사용하면 된다.

  • 요청 매핑 애노테이션 적용 메서드에 HttpSession 파라미터를 추가한다.
  • 요청 매핑 애노테이션 적용 메서드에 HttpServletRequest 파라미터를 추가하고 HttpServletRequest을 이용해서 HttpSession을 구한다.

2.1 메서드에 HttpSession 파라미터 추가

1
2
3
4
@PostMapping
public String form(LoginCommand loginCommand, Errors errors, HttpSession session) {
    ...//session을 사용하는 코드
}

요청 매핑 애노테이션 적용 매서드에 HttpSession 파라미터가 존재할 경우 스프링 MVC는 컨트롤러의 메서드를 호출할 때 HttpSession 객체를 파라미터로 전달한다.
HttpSession을 생성하기 전이면 새로운 HttpSession을 생성하고 그렇지 않으면 기존에 존재하는 HttpSession을 전달한다.

2.2 HttpServletRequest의 getSession() 메서드 이용

1
2
3
4
5
6
@PostMapping
public String submit(
    LoginCommand loginCommand, Errors errors, HttpServletRequest req){
        HttpSession session = req.getSession();
        ...// sessio을 사용하는 코드
    }

두 번째 방법은 HttpServletRequestdml getSession() 메서드를 이용하는 것이다.

첫 번째 방법은 항상 HttpSession을 생성하지만
두 번째 방법은 필요한 시점에만 HttpSession을 생성할 수 있다.

2.3 HttpSession 사용

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
@Controller
@RequestMapping("/login")
public class LoginController {
    ...

    PostMapping
    public String submit(
        @Valid LoginCommand loginCommand, Errors errors, HttpSession session){
        
        if(errors.hasErrors()) {
            return "login/loginForm";
        }
        try{
            AuthInfo authInfo = authService.authenticate(
                loginCommand.getEmail(), loginCommand.getPassword());
            
            session = setAttribute("authInfo", authInfo);

            return "login/loginSuccess";
        }catch(IdPasswordNotMatchingException e){
            errors.reject("idPasswordNotMatching");
            return "login/loginForm";
        }
    }
}

로그인에 성공하면 17행 HttpSession의 “authInfo” 속성에 인증 정보 객체(authInfo)를 저장하도록 코드를 추가했다.
로그아웃을 위한 컨트롤러 클래스는 HttpSession을 제거하면 된다. 로그아웃 처리를 위한 LogoutController는 다음과 같다.

1
2
3
4
5
6
7
8
@Controller
public class LogoutController{
    @RequestMapping("/logout")
    public String logout(HttpSession session){
        session.invalidate();
        return "redirect:/main";
    }
}

Ref.

  • 최범균, 스프링프로그래밍입문5, 가메출판사.

카테고리:

업데이트: