[Spring Boot] 로그인 기능 구현 (1) - 쿠키 로그인

2024. 1. 7. 12:43· Spring Boot
목차
  1. 1. 쿠키란 ?
  2. 2. 쿠키 생성, 추가, 읽기
  3. 2-1. 쿠키 생성
  4. 2-2. 쿠키 속성 설정
  5. 2-3. 쿠키 저장
  6. 2-4. 컨트롤러에서 쿠키 정보 읽기
  7. 2-5. 쿠키 삭제
  8. 3. 로그인 프로젝트에 적용
  9. 3-1. CookieLoginController
  10. 4. 실행결과
  11. 5. 보안 고려사항

2024.01.07 - [Spring Boot] - [Spring Boot] 로그인 기능 구현 (0) - 공통 기능, 코드 구현

 

[Spring Boot] 로그인 기능 구현 (0) - 공통 기능, 코드 구현

0. 상황 설명 여러가지 방법을 사용해서 로그인 기능을 구현하려 함 공통인 기능과 코드는 이 게시글에서 모두 정리 방법마다 다른 코드는 각 게시물에서 따로 정리 1. 프로젝트 버전 정보 / DB 스

blogan99.tistory.com

 

1. 쿠키란 ?

  • 사이트에 방문 시, 브라우저는 서버에 request 보냄
  • 서버는 이에 응답 (response) 해서 데이터와 페이지 정보등을 넘김 => response에는 브라우저에 저장하고자 하는 쿠키 존재 가능
  • 서버가 생성한 쿠키는 브라우저로 전달되고 클라이언트는 이를 저장함
  • 다음에 사이트에 방문 시, 클라이언트의 브라우저는 저장된 쿠키를 request와 함께 보냄
  • 즉 쿠키는 사용자의 정보를 기억하고 식별하는데 사용되며 데이터를 전달하는 매개체임
  • 제약 조건
    • 도메인에 제한적 ( ex. 유튜브에서 보낸 쿠키는 유튜브로만 다시 보내짐)
    • 유효기간 존재
    • 공간적 제약

 

2. 쿠키 생성, 추가, 읽기

  • 쿠키의 기본 구조

    Set-Cookie: name=value; expires=[Date]; domain=[Domain]; path=[Path]; [secure]
    • name=value
      • 쿠키의 이름과 값 설정 (필수 항목)
      • 서버와 브라우저가 쿠키를 식별하고 저장하는데 사용
    • expires=[Date]
      • 쿠키의 유효기간 설정
      • 설정하지 않으면 쿠키는 세션 쿠키가 됨 => 브라우저가 닫히면 쿠키가 삭제됨
    • domain=[Domain]
      • 쿠키가 유효한 도메인 설정
      • 설정하지 않으면 쿠키를 생성한 서버의 도메인으로 자동 설정
    • path=[Path]
      • 쿠키가 유효한 경로 설정
      • 도메인 내의 특정 부분으로, 쿠키가 전송될 URL 제한함
      • 기본적으로는 쿠키를 생성한 경로에서만 쿠키 사용가능 , '/' 로 설정 시 도메인의 모든 페이지에서 쿠키 사용 가능
    • [secure]
      • 설정되면 쿠키는 HTTPS 프로토콜을 통해서만 전송됨
      • 보안 연결이 유지되는 동안에만 쿠키 데이터가 노출되도록 함
    • HttpOnly : JavaScript와 같은 클라이언트 사이드 스크립트에서 쿠키 접근 못하도록 막음
    • SameSite : 브라우저가 같은 사이트 요청만 쿠키를 전송하도록 제한, CSRF 공격 방지하는데 유용

 

2-1. 쿠키 생성

  • HttpServletResponse 객체 사용
  • 필수적으로 name과 value 지정해야 함
// 쿠키 생성
Cookie cookie = new Cookie("쿠키 이름", "쿠키 값");

 

2-2. 쿠키 속성 설정

  • 위에서 언급한 기본 구조에 해당하는 속성 설정 (필수 x)
// 쿠키 유효기간 설정 => 1시간
cookie.setMaxAge(60 * 60);

// 쿠키 유효도메인 설정 => localhost
cookie.setDomain("localhost");

// 쿠키 유효경로 설정 => 도메인의 모든 페이지
cookie.setPath("/");

// 쿠키 보안 설정 => HTTPS 프로토콜을 통해서만 전송
cookie.setSecure(true);

// 클라이언트 사이드 스크립트의 쿠키 접근 제한
cookie.setHttpOnly(true);

 

2-3. 쿠키 저장

  • 클라이언트에 보내기 위해서 HttpServletResponse에 쿠키 추가
// HttpServletResponse response

// 쿠키 저장
response.addCookie(cookie);

 

2-4. 컨트롤러에서 쿠키 정보 읽기

  • @CookieValue 어노테이션 사용해서 클라이언트에게 받은 요청에 포함된 쿠키의 값 읽기
@GetMapping("/info")
public String info(@CookieValue(name = "userId", required = false) Long userId){
	System.out.println("쿠키 정보 읽기 (userId) : " + userId);	// 읽어온 쿠키 정보 출력
}

 

2-5. 쿠키 삭제

  • 동일한 이름의 쿠키를 생성하고 유효기간을 0으로 설정함 => 이 쿠키를 클라이언트에 다시 보냄으로써 쿠키 삭제
// 동일한 이름의 쿠키 생성
Cookie cookie = new Cookie("동일 쿠키 이름", null);

// 쿠키의 수명을 0으로 설정
cookie.setMaxAge(0);

// HttpServletResponse에 수명이 다 한 cookie 추가 => 쿠키 삭제
response.addCookie(cookie);

 

3. 로그인 프로젝트에 적용

  • 로그인을 제외한 나머지 기능, 라이브러리 등은 아래 게시글 참고

2024.01.07 - [Spring Boot] - [Spring Boot] 로그인 기능 구현 (0) - 공통 기능, 코드 구현

 

[Spring Boot] 로그인 기능 구현 (0) - 공통 기능, 코드 구현

0. 상황 설명 여러가지 방법을 사용해서 로그인 기능을 구현하려 함 공통인 기능과 코드는 이 게시글에서 모두 정리 방법마다 다른 코드는 각 게시물에서 따로 정리 1. 프로젝트 버전 정보 / DB 스

blogan99.tistory.com

 

3-1. CookieLoginController

  • home
    @GetMapping(value = {"", "/"})
    public String home(@CookieValue(name = "memberId", required = false)
                           Long memberId, Model model) {
        
        // 화면에 출력하기 위해 model에 속성 추가
        model.addAttribute("loginType", "cookie-login");
        model.addAttribute("pageName", "쿠키 로그인");

        Member loginMember = memberService.getLoginMemberById(memberId);

		// 로그인 되어있다면 model에 이름 속성 추가
        if (loginMember != null) {
            model.addAttribute("name", loginMember.getName());
        }

        return "home";
    }
  • @CookieValue를 통해서 쿠키의 값을 읽어옴
    • 쿠키의 name에 해당하는 값이 존재한다면 로그인 한 것 => model에 속성 추가
    • 존재하지 않으면 로그인 하지 않은 것 => model에 name이 null로 들어있음

 

  • join
    @GetMapping("/join")
    public String joinPage(Model model) {
        model.addAttribute("loginType", "cookie-login");
        model.addAttribute("pageName", "쿠키 로그인");
		
        // 회원가입을 위해서 model 통해서 joinRequest 전달 
        model.addAttribute("joinRequest", new JoinRequest());
        return "join";
    }

    @PostMapping("/join")
    public String join(@Valid @ModelAttribute JoinRequest joinRequest,
                       BindingResult bindingResult, Model model) {

        model.addAttribute("loginType", "cookie-login");
        model.addAttribute("pageName", "쿠키 로그인");

		// ID 중복 여부 확인
        if(memberService.checkLoginIdDuplicate(joinRequest.getLoginId())){
            bindingResult.addError(new FieldError
                    ("joinRequest",
                    "loginId",
                    "ID가 존재합니다."));
        }

		// 비밀번호 = 비밀번호 체크 여부 확인
        if(!joinRequest.getPassword().equals(joinRequest.getPasswordCheck())){
            bindingResult.addError(new FieldError(
                    "joinRequest",
                    "passwordCheck",
                    "비밀번호가 일치하지 않습니다"));
        }

		// 에러가 존재할 시 다시 join.html로 전송
        if (bindingResult.hasErrors()) {
            return "join";
        }

		// 에러가 존재하지 않을 시 joinRequest 통해서 회원가입 완료
        memberService.join(joinRequest);
        
        // 회원가입 시 홈화면으로 이동
        return "redirect:/cookie-login";
    }
  • ID 중복, 비밀번호 체크 확인
    • bindingResult.addError 통해서 field error 추가 => 화면에서 field error 출력 위해서
  • 에러가 존재하면 다시 입력할 수 있게 join.html로 이동
  • 에러가 존재하지 않으면 회원가입 진행 후 홈화면으로 이동

 

  • login
    @GetMapping("/login")
    public String loginPage(Model model) {
    
        model.addAttribute("loginType", "cookie-login");
        model.addAttribute("pageName", "쿠키 로그인");

        model.addAttribute("loginRequest", new LoginRequest());
        return "login";
    }

    @PostMapping("/login")
    public String login(@ModelAttribute LoginRequest loginRequest, BindingResult bindingResult,
                        HttpServletResponse response, Model model) {
                        
        model.addAttribute("loginType", "cookie-login");
        model.addAttribute("pageName", "쿠키 로그인");

        Member member = memberService.login(loginRequest);

        // ID나 비밀번호가 틀린 경우 global error return
        if(member == null) {
            bindingResult.reject("loginFail", "로그인 아이디 또는 비밀번호가 틀렸습니다.");
        }

        if(bindingResult.hasErrors()) {
            return "login";
        }

        // 로그인 성공 => 쿠키 생성
        Cookie cookie = new Cookie("memberId", String.valueOf(member.getId()));
        cookie.setMaxAge(60 * 60);  // 쿠키 유효 시간 : 1시간
        response.addCookie(cookie);

        return "redirect:/cookie-login";
    }
  • @ModelAttribute로 받아온 loginRequest 정보를 통해서 로그인 진행
    • ID나 비밀번호가 틀리면 로그인 되지 않음
      • bindingResult.reject 통해서 global error 추가
      • 화면에서 global error 출력
    • 로그인 성공 시 쿠키 생성, 저장
      • 쿠키에 ID값 저장, 유효기간 1시간으로 설정
      • response.addCookie(cookie) 통해서 쿠키 저장
  • 로그인 후 홈 화면으로 리턴

 

  • logout
    @GetMapping("/logout")
    public String logout(HttpServletResponse response, Model model) {
    
        model.addAttribute("loginType", "cookie-login");
        model.addAttribute("pageName", "쿠키 로그인");

		// 동일한 이름의 새 쿠키 생성 => 로그아웃
        Cookie cookie = new Cookie("memberId", null);
        cookie.setMaxAge(0);
        response.addCookie(cookie);
        return "redirect:/cookie-login";
    }
  • "memberId"의 이름을 가진 새 쿠키 생성하고 유효기간 0으로 설정
  • response.addCookie(cookie)를 통해서 유효하지 않은 쿠키 전달 => 로그아웃
  • 로그아웃 시 홈 화면으로 리턴

 

  • info
    @GetMapping("/info")
    public String info(@CookieValue(name = "memberId", required = false) Long memberId, Model model) {

        model.addAttribute("loginType", "cookie-login");
        model.addAttribute("pageName", "쿠키 로그인");

        Member loginMember = memberService.getLoginMemberById(memberId);

        if(loginMember == null) {
            return "redirect:/cookie-login/login";
        }

        model.addAttribute("member", loginMember);
        return "info";
    }
  • 로그인 된 멤버 찾음
    • 로그인 되어 있으면 model에 loginMember 넣어서 전달

 

  • admin
    @GetMapping("/admin")
    public String adminPage(@CookieValue(name = "memberId", required = false) Long memberId, Model model) {
        
        model.addAttribute("loginType", "cookie-login");
        model.addAttribute("pageName", "쿠키 로그인");

        Member loginMember = memberService.getLoginMemberById(memberId);

        if(loginMember == null) {
            return "redirect:/cookie-login/login";
        }

        if(!loginMember.getRole().equals(MemberRole.ADMIN)) {
            return "redirect:/cookie-login";
        }

        return "admin";
    }
  • 로그인 된 멤버 찾음
    • 멤버의 role이 ADMIN이 아니라면 홈 화면으로 이동
    • 멤버의 role이 ADMIN이 맞다면 admin.html로 이동

 

4. 실행결과

  • 홈 화면

  • 회원가입 화면

  • 회원가입 화면 (오류)

  • 로그인 화면

  • 로그인 화면 (오류)

  • 로그인 후 홈 화면

  • 마이페이지

  • 관리자 계정으로 들어간 관리자 페이지

 

5. 보안 고려사항

  • 개발자 도구로 들어가면 생성된 쿠키의 정보를 볼 수 있음

  • 쿠키의 정보를 암호화해서 보안 강화 가능
  • 유효 기간을 적절히 설정해서 보안 강화 가능
  • CSRF(Cross-Site Request Forgery) 공격에 대비해서 적절한 대책 마련 필요
저작자표시 변경금지 (새창열림)

'Spring Boot' 카테고리의 다른 글

[Spring Boot] 로그인 기능 구현 (3) - 스프링 시큐리티 로그인  (4) 2024.01.07
[Spring Boot] 로그인 기능 구현 (2) - 세션 로그인  (0) 2024.01.07
[Spring Boot] 로그인 기능 구현 (0) - 공통 기능, 코드 구현  (2) 2024.01.07
[Spring Boot] 페이징 기능 구현 ( + 페이징, 정렬, 검색, 에러 메시지 포함 예제)  (1) 2024.01.03
[SpringBoot] MySQL 연동 (maven, gradle)  (0) 2023.12.12
  1. 1. 쿠키란 ?
  2. 2. 쿠키 생성, 추가, 읽기
  3. 2-1. 쿠키 생성
  4. 2-2. 쿠키 속성 설정
  5. 2-3. 쿠키 저장
  6. 2-4. 컨트롤러에서 쿠키 정보 읽기
  7. 2-5. 쿠키 삭제
  8. 3. 로그인 프로젝트에 적용
  9. 3-1. CookieLoginController
  10. 4. 실행결과
  11. 5. 보안 고려사항
'Spring Boot' 카테고리의 다른 글
  • [Spring Boot] 로그인 기능 구현 (3) - 스프링 시큐리티 로그인
  • [Spring Boot] 로그인 기능 구현 (2) - 세션 로그인
  • [Spring Boot] 로그인 기능 구현 (0) - 공통 기능, 코드 구현
  • [Spring Boot] 페이징 기능 구현 ( + 페이징, 정렬, 검색, 에러 메시지 포함 예제)
공대생안씨
공대생안씨
전자공학과 학부생의 코딩 일기
공대생의 코딩 일기전자공학과 학부생의 코딩 일기
티스토리
|
로그인
공대생안씨
공대생의 코딩 일기
공대생안씨
글쓰기
|
관리
전체
오늘
어제
  • All Categories (153)
    • Spring Boot (46)
      • JPA (7)
      • Lombok (2)
    • Java (21)
    • DevOps (3)
      • CI,CD (8)
      • Monitoring (2)
    • Database (7)
      • MySQL (5)
      • MongoDB (1)
      • H2 (1)
    • Trouble Shooting (5)
    • FE (4)
    • IntelliJ (3)
    • Git (3)
    • Algorithm (41)

블로그 메뉴

  • 홈
  • 태그
  • Github

공지사항

인기 글

hELLO · Designed By 정상우.v4.2.2
공대생안씨
[Spring Boot] 로그인 기능 구현 (1) - 쿠키 로그인
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.