티스토리 뷰

반응형

springMvc2_Login

스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - (로그인 처리)

쿠키는 브라우저에 담겨, 모든 요청이 있을 때마다 서버도 전달된다.

image-20220423182740653

쿠카는 영속쿠키와 세션쿠키가 있다

  • 영속 쿠키 : 만료 날짜를 입력하면 해당 날짜까지 유지된다.
  • 세션 쿠키 : 만료 날짜를 생략하면 브라우저 종료시 까지만 유지된다.
    브라우저 종료시 로그아웃이 되길 기대하므로, 우리에게 필요한 것은 세션 쿠키이다.??
  • 이상하네 우리는 요청 할 때마다 연장되는거였으니까 세션쿠키가 아니라 영속쿠키를 한거아냐???????

그렇다면 로그인과 로그아웃 처리를 Cookie를 통해 해보자

LoginController.java
// 로그인
Cookie idCookie = new Cookie("memberId", String.valueOf(loginMember.getId()));
httpResponse.addCookie(idCookie);

// 로그아웃
@PostMapping("/logout")
public String logout(HttpServletResponse response){
  expireCookie(response, "memberId");
  return "redirect:/";
}

private void expireCookie(HttpServletResponse response, String cookieName) {
  Cookie cookie = new Cookie("memberId", null);
  cookie.setMaxAge(0); // 해당 쿠키의 종료날짜를 0으로 지정한다.
  response.addCookie(cookie);
}
 

하지만 저렇게 쿠키값으로만 로그인 로그아웃을 한다면,
쿠키는 값을 임의로 변경할 수 있기때문에 다른 사용자로도 변신할 수 있다.

대안 [세션] 이용하기

  1. 쿠키에 중요한 값을 노출시키지 않고 예측 불가능한 임의의 토큰값을 노출한다.
  2. 서버에서 토큰값을 사용자id와 매핑해서 인식한다.
    단, 토큰은 만료시간을 짧게 유지한다(30분)
  3. 토큰은 해당 서버에서 관리한다.

세션을 어떻게 할 것인지 전체 개념을 이해해보자

  1. 사용자가 loginId, password를 전달하면, 서버는 해당 사용자가 맞는지 확인을 한다.

image-20220423185228083



2. 해당 사용자가 맞을 경우 UUID라는 랜덤값을 생성하여 세션저장소에 담아둔다.
생성된 세션ID와 세션에 보관할 값(Member객체)을 세션 저장소에 보관한다.

  • Cookie: mySessionId=zz0101xx-bab9-4b92-9b32-dadb280f4b61

image-20220423185418752



3. sessionId를 담아 쿠키로 전달한다.

  • 클라이언트와 서버는 결국 쿠키로 연결이 되어야 한다

image-20220423185607953



여기서 중요한 포인트는 회원과 관련된 정보는 클라이언트에 전달하지 않는것
또한, 추정 불가능한 세션 ID만 쿠키를 통해 클라이언트에 전달한다.

  1. 로그인 이후
  • 클라이언트의 요청 시 항상 sessionId를 전달한다.
  • 서버에서는 클라이언트가 전달한 sessionId 쿠키정보로
    세션 저장소를 조회해서 로그인 시 보관한 세션 정보를 사용한다.

정리

세션저장소에 sessionId(uuid)를 저장하고 sessionId(uuid)만을 클라이언트 브라우저에 저장할 경우
아래와 같은 보안문제들을 해결할 수 있다.

문제 해결
쿠키 값 변조 가능 예상 불가능한 복잡한 세션Id를 사용
쿠키를 보관하는 정보는 클라이언트 해킹 시 털릴 가능성이 있다. 세션Id에는 중요한 정보가 없다.
쿠키 탈취 후 사용 세션 만료시간을 30분 정도로 짧게 유지하고
클라이언트 요청이 있을 때마다 유지시간을 연장한다.
또한, 해킹이 의심되는 경우 세션을 강제로 제거한다.

세션관리는 크게 3가지로 나뉜다.

  1. 세션 생성
    • sessionId 생성 (임의의 추정 불가능한 랜덤 값)
    • 세션 저장소에 sessionId와 보관할 값을 저장
  2. 세션 조회
    • 클라이언트가 요청한 sessionId쿠키의 값으로, 세션저장소에 보관할 값 조회
  3. 세션 만료
    • 클라이언트가 요청한 sessionId쿠키의 값으로, 세션 저장소에 보관한 sessionId 값 제거

Servlet이 제공하는 HttpSession을 사용하여 만들어보자

HttpSession을 사용하면 Cookie이름이 JSEESSIONID으로 값은 불가능한 랜던값이 생성된다.

Cookie: JSESSIONID=5B78E23B513F50164D6FDD8C97B0AD05
 

1. 세션 생성

HttpSession session = request.getSession(true); // defalt가 true
session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember);
 
구분 세션 O 반환값 세션 X 반환값
request.getSession(true) 기존 세션 새로 생성
request.getSession(false) 기존 세션 Null
@PostMapping("/login")
public String login(@Valid @ModelAttribute LoginForm loginForm, BindingResult bindingResult, HttpServletRequest request){
  if(bindingResult.hasErrors()){
    return "login/loginForm";
  }

  Member loginMember = loginService.login(loginForm.getLoginId(), loginForm.getPassword());

  if(loginMember == null){
    bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다.");
    return "login/loginForm";
  }

  HttpSession session = request.getSession(true); // defalt가 true
  session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember);

  return "redirect:/";
}
 

image-20220423204952378

image-20220423205052020

2. Home 진입 시 Session 가져오기

HttpSession session = request.getSession(false);
if(session == null){
  return "home";
}

Member member = (Member) session.getAttribute(SessionConst.LOGIN_MEMBER);
 

위 5줄 짜리 소스를 아래 어노테이션으로 한번에 처리 가능하다

public String homLogin4(
  @SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false) Member member
  , Model model){
 
@GetMapping("/")
public String homLogin4(
  @SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false) Member member, Model model){

  //        // Home화면 진입이기때문에
  //        // 세션을 생성할 의도가 없기에 getSssion(false)로 지정해줘야한다.
  //        HttpSession session = request.getSession(false);
  //        if(session == null){
  //            return "home";
  //        }
  //
  //        Member member = (Member) session.getAttribute(SessionConst.LOGIN_MEMBER);

  if(member == null){
    return "home";
  }

  if(member == null){
    return "home";
  }

  model.addAttribute("member", member);
  return "loginHome";
}
 

3. 세션 만료

  • HttpSession session = request.getSession(false);
  • session.invalidate();
@PostMapping("/logout")
public String logout3(HttpServletRequest request){
  HttpSession session = request.getSession(false);
  if(session != null){
    session.invalidate(); // 무효화하다 invalidate
  }
  return "redirect:/";
}
 

그런데 URL에 JSESSIONID로 아래와 같이 들어오기때문에
브라우저에서 쿠키를 지원하지 않는 경우로 만들어진 것이다.

image-20220423205910738

Application.properties에 다음 내용을 넣어주자

server.servlet.session.tracking-modes=cookie
 

- 영속쿠키
- 세션쿠키
- Cookie cookie = new Cookie(“memberId”, String.valueOf(loginMember.getId());  
           HttpResponse.addCookie(cookie);
  - Cookie cookie = new Cookie(“memberId”, null);
       cookie.setMaxAge(0);
       response.addCookie(cookie);

 - 세션
1. 세션 생성
  HttpSession session = request.getSession(true); // defalt가 true
  session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember);

 2. 세션만료
  HttpSession session = request.getSession(false);
  if(session != null){
    session.invalidate(); // 무효화하다 invalidate
  }

3. 세션가져오기
HttpSession session = request.getSession(false);
Member member = (Member) session.getAttribute(SessionConst.LOGIN_MEMBER);
   ===> @SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false) Member member
 
server.servlet.session.timeout=1800 !!!!!
반응형
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
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
글 보관함