로그인, 로그아웃 기능 구현

루민 ·2023년 4월 2일
0

📖로그인 기능

@GetMapping("/members")

   public String loginForm(Model model) {
        model.addAttribute("loginForm", new LoginForm());
        return "members/loginForm";
    }
  • loginForm(DTO)를 모델을 통해 뷰로 전달해주었습니다.


LoginForm

@Getter
@Setter
public class LoginForm {

    @NotEmpty(message = "이메일 주소는 필수입니다.")
    @Email  //이메일 형식 validation
    private String email;
    @NotEmpty(message = "비밀번호를 입력해주세요")
    private String password;
}


@PostMapping("/members")

@PostMapping("/members")
    public String login(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult, HttpServletRequest request) {

        //이메일 또는 비밀번호를 누락시
        if(bindingResult.hasErrors()) {
            log.info("error={}", bindingResult);
            return "members/loginForm";
        }

        Member loginMember = memberService.login(form.getEmail(), form.getPassword());
        log.info("login? {}", loginMember);

        if (loginMember == null) {
            bindingResult.reject("loginfail", "이메일 또는 비밀번호가 맞지 않습니다.");
            return "members/loginForm";
        }

        /**
         * HttpSession 생성
         */
        HttpSession session = request.getSession();  //만약 세션이 있으면 기존 세션을 반환하고, 없으면 신규 세션 생성
        session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember);  //세션에 회원 정보 보관

        //판매자, 구매자 역할 뷰 나누기 TODO
        return "redirect:/userHome";
    }
  • LoginForm의 @NotEmpty, @Email 어노테이션으로 인해 post 로 넘어올 때 bindResult에 오류 값이 넘어오게 됩니다. 만약 이메일 형식이 아니거나 이메일이나 비밀번호를 누락시 bindingResult에는 오류 값이 넘어오게 됩니다.
  • memberService.login을 통해 데이터베이스에 저장되어있는 회원의 이메일, 비밀번호를 검증합니다.
  • memberService.login은 회원의 이메일과 비밀번호가 일치 하지 않을 시 null을 반환하게 하였습니다.
  • 로그인 검증의 경우 객체 필드의 오류(@NotEmpty, @Email ...)만으로는 판단이 불가합니다. 즉, 데이터베이스 안까지 뒤져서 검증을 해야합니다.
    Null을 반환하게 되면 bindingResult.reject로 뷰에서 글로벌 오류를 출력하게 합니다.
  • 서블릿이 제공하는 request.getSession()으로 신규 세션을 생성하였고 세션에 회원정보를 보관하였습니다.

    request.getSession(true) : 세션이 있으면 기존 세션을 반환, 세션이 없으면 신규 세션 생성해서 반환
    request.getSession(false) : 세션이 있으면 기존 세션을 반환, 세션이 없어도 신규 세션을 생성하지 않고 null을 반환

  • 세션을 생성하면 이름이 JSESSIONID인 쿠키를 생성합니다. 쿠키의 값은 거의 추정이 불가능한 랜덤 값으로 할당됩니다.

server.servlet.session.tracking-modes=cookie
  • URL에 jessionid가 노출되는 것을 방지하고 URL 전달 방식이 아니 항상 쿠키를 통해서만 세션을 유지하기 위해 application.properties 파일에 추가해줍니다.
  • 세션의 종료 시점 : 서블릿이 제공하는 HttpSession의 세션은 기본적으로 사용자가 서버에 최근에 요청한 시간을 기준으로 30분 정도를 유지합니다.
  • 세션의 타임아웃을 따로 설정도 가능합니다.


MemberSerivce

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)  //조회하는 곳에서 성능 최적화
public class MemberService {

    private final MemberRepository memberRepository;


    //회원가입
    @Transactional(readOnly = false)
    public Long join(Member member) {
        validateDuplicateMember(member);
        Member savedMember = memberRepository.save(member);
        return savedMember.getId();
    }

    //중복 회원 검증
    private void validateDuplicateMember(Member member) {
        Member findMember = memberRepository.findByEmail(member.getEmail()).orElse(null);
        if (findMember != null) {
            throw new IllegalStateException("이미 존재하는 회원입니다");
        }
    }

    //로그인 체크(null 이면 로그인 실패)
    public Member login(String email, String password) {
        return memberRepository.findByEmail(email)
                .filter(m -> m.getPassword().equals(password))
                .orElse(null);
    }

    public Member findMember(Long id) {
        return memberRepository.findById(id).get();
    }

    public List<Member> findMembers() {
        return memberRepository.findAll();
    }
}


📖로그아웃 기능

@GetMapping("/logout")

 /**
     * 로그아웃
     */
    @GetMapping("/logout")
    public String logout(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session != null) {
            session.invalidate();
        }
        return "redirect:/";
    }


📖결과 화면

1. 이메일 또는 비밀번호 누락시


2. 이메일 또는 비밀번호가 맞지 않을 때


3. 로그인 성공

  • 메인 화면은 아직 미완성입니다!

0개의 댓글