[회원관리] 로그인

2023. 1. 3. 16:40프로젝트/라이어게임

728x90
SMALL

로그인 API

기능 Method URL Request Response 비고
로그인 POST /lier/login {
”email”:”wlstpgns51@naver.com”,
”password”:”wls1234!”
}
data{
”email”:””,
”nickname”:””
}
+
response
 

1. POST 형식

2. Request 요청은 DTO 형식으로 이메일과 비밀번호 두가지만 필요하도록 했다.

3. Response 응답값은 json 형식으로 data 안에 로그인된 이메일과 닉네임이 반환 + Response에 토큰을 넣는다.


MemberController

// 로그인
@PostMapping(value = "/login")
public ResponseEntity<PrivateResponseBody> login(
         @RequestBody LoginRequestDto requestDto,
         HttpServletResponse response) {
     log.info("로그인 - 아이디 : {}, 비밀번호 : {}", requestDto.getEmail(), requestDto.getPassword());
     return memberService.login(requestDto, response);
 }
  • @RequestBody로 json 형태의 LoginRequestDto 이메일과 비밀번호를 넣어 Service단에 넘긴다.
  • 로그인이 정상적으로 된다면 인증을 통해 Response 헤더에 토큰을 넣어서 반환하기 때문에 HttpServletResponse를 Service 단으로 넘긴다.

 

 

MemberService

// 로그인
@Transactional
public ResponseEntity<PrivateResponseBody> login(LoginRequestDto requestDto, HttpServletResponse response) {
     // 로그인 시도한 이메일 아이디가 존재하는 아이디인지 확인 후 저장
     Member member = isPresentMember(requestDto.getEmail());

     // DB에 해당 아이디를 가진 멤버가 없다면 에러 처리
     if (null == member) {
         return new ResponseEntity<>(new PrivateResponseBody
                 (StatusCode.LOGIN_MEMBER_ID_FAIL, null), HttpStatus.BAD_REQUEST);
     }

     // 로그인 시도한 비밀번호를 인코딩하여 존재하는 비밀번호와 일치하는지 확인
     if (!member.validatePassword(passwordEncoder, requestDto.getPassword())) {
         return new ResponseEntity<>(new PrivateResponseBody
                 (StatusCode.LOGIN_PASSWORD_FAIL, null), HttpStatus.BAD_REQUEST);
     }

     //토큰 지급
     TokenDto tokenDto = tokenProvider.generateTokenDto(member);
     // response에 토큰을 담는다
     tokenToHeaders(tokenDto, response);

     // 전달드릴 내용이 매우 적기 때문에 굳이 Dto를 생성하지 않고 hashmap으로 전달
     HashMap<String, String> login_info = new HashMap<>();
     login_info.put("email", member.getEmail()); // 이메일
     login_info.put("nickname", member.getNickname()); // 닉네임

     log.info("액세스 토큰 : {}", response.getHeader("Authorization"));
     log.info("리프레시 토큰 : {}", response.getHeader("Refresh-Token"));

     // Message 및 Status를 Return
     return new ResponseEntity(new PrivateResponseBody(StatusCode.LOGIN_OK, login_info), HttpStatus.OK);
}
  • isPresentMember에 입력받은 이메일을 넣어 유저 정보를 불러온다.
  • 유저 정보가 존재하지 않는다면 오류 처리를 한다.
  • validatePassword 메소드에 passwordEncoder, 입력받은 비밀번호를 넣어 현재 불러온 유저 정보의 인코딩된 비밀번호와 입력받은 비밀번호가 매칭(matches())이 되는지 확인한다.
public boolean validatePassword(PasswordEncoder passwordEncoder, String password) {
    return passwordEncoder.matches(password, this.password);
}
  • TokenProvider의 GenerateTokenDto에 불러온 유저 정보를 넣어 AccessToken, RefreshToken을 만든다.
public TokenDto generateTokenDto(Member member) {
  long now = (new Date().getTime());

  Date accessTokenExpiresIn = new Date(now + ACCESS_TOKEN_EXPIRE_TIME);
  String accessToken = Jwts.builder()
      .setSubject(member.getEmail())
      .claim(AUTHORITIES_KEY, Authority.ROLE_MEMBER.toString())
      .setExpiration(accessTokenExpiresIn)
      .signWith(key, SignatureAlgorithm.HS256)
      .compact();

  String refreshToken = Jwts.builder()
      .setExpiration(new Date(now + REFRESH_TOKEN_EXPRIRE_TIME))
      .signWith(key, SignatureAlgorithm.HS256)
      .compact();

  RefreshToken refreshTokenObject = RefreshToken.builder()
      .id(member.getMemberId())
      .member(member)
      .value(refreshToken)
      .build();

  refreshTokenRepository.save(refreshTokenObject);

  return TokenDto.builder()
      .grantType(BEARER_PREFIX)
      .accessToken(accessToken)
      .accessTokenExpiresIn(accessTokenExpiresIn.getTime())
      .refreshToken(refreshToken)
      .build();

}
  • RefreshToken은 따로 RefreshToken Entity에 저장한다.

RefreshToken

package com.example.finalproject.domain;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class RefreshToken extends Timestamped {

  @Id
  @Column(nullable = false)
  private Long id;

  @JoinColumn(name = "memberId", nullable = false)
  @OneToOne(fetch = FetchType.LAZY)
  private Member member;

  @Column(nullable = false)
  private String value;

}
  • TokenDto에 생성한 토큰 정보들, 토큰 만료시간, 권한 정보를 builder로 대입하여 반환한다.
return TokenDto.builder()
    .grantType(BEARER_PREFIX)
    .accessToken(accessToken)
    .accessTokenExpiresIn(accessTokenExpiresIn.getTime())
    .refreshToken(refreshToken)
    .build();
  • 반환된 TokenDto와 HttpServletResponse를 tokentoHeaders 메소드에 넣어 Response에 토큰을 넣는다.
// response에 토큰을 담는다
tokenToHeaders(tokenDto, response);
  • Response에 토큰을 넣어서 반환함과 동시에 로그인된 정보를 HashMap으로 반환하여 결과를 알려준다.
// 전달드릴 내용이 매우 적기 때문에 굳이 Dto를 생성하지 않고 hashmap으로 전달
HashMap<String, String> login_info = new HashMap<>();
login_info.put("email", member.getEmail()); // 이메일
login_info.put("nickname", member.getNickname()); // 닉네임

log.info("액세스 토큰 : {}", response.getHeader("Authorization"));
log.info("리프레시 토큰 : {}", response.getHeader("Refresh-Token"));

// Message 및 Status를 Return
return new ResponseEntity(new PrivateResponseBody(StatusCode.LOGIN_OK, login_info), HttpStatus.OK);

로그인이 정상적으로 되었다.

다음은 로그아웃을 정리해보자.

728x90
반응형
LIST

'프로젝트 > 라이어게임' 카테고리의 다른 글

[회원관리] 회원가입  (0) 2022.12.30
프로젝트 세팅  (0) 2022.12.30
[회원관리] Jwt를 활용한 회원관리 기능 세팅  (0) 2022.12.28
서비스 아키텍쳐  (0) 2022.12.15