회원가입 및 로그인 인증처리 (작성중)

no.oneho·2023년 10월 31일
0

이번에는 회원가입및 로그인 인증처리 포스팅을 작성해보겠다.

UserDetailsService 를 상속받아 사용하는 방식이 일반적이지만 나는 사용하지않고 구현해보았다.

앞서 의존성을 받아준다

implementation 'org.springframework.boot:spring-boot-starter-security'
implementation group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.1'

testImplementation 'org.springframework.security:spring-security-test'

회원가입은 간단하다

회원가입에 request로 사용할 dto를 하나 선언해준다.

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "회원가입 요청 DTO")
public class SignupRequest {

    @NotBlank
    @ApiModelProperty(value = "이메일 입력 필드", dataType = "String")
    private String email;
    @NotBlank
    @ApiModelProperty(value = "패스워드 입력 필드", dataType = "String")
    private String password;
    @NotBlank
    @ApiModelProperty(value = "패스워드 확인 입력 필드", dataType = "String")
    private String passwordCheck;
    @NotBlank
    @ApiModelProperty(value = "닉네임 입력 필드", dataType = "String")
    private String nickname;

    @ApiModelProperty(value = "이미지 파일 입력 필드", dataType = "MultipartFile")
    private MultipartFile profileFile;

}
    @PostMapping(value = "/signup", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    @Operation(summary = "회원 가입 API", description = "폼데이터로 요청")
    public Response<LoginResponse> signup(@ModelAttribute SignupRequest signupRequest) {

        return ApiUtils.success(HttpStatus.CREATED, "회원 가입 성공", userService.signup(signupRequest));
    }

스펙에 따라 컨트롤러에서 요청을 받고


	private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;

    @Transactional
    public LoginResponse signup(SignupRequest signupRequest) {
        checkDuplicateEmail(signupRequest.getEmail());
        checkConfirmPassword(signupRequest.getPassword(), signupRequest.getPasswordCheck());
        User user = User.from(signupRequest, passwordEncoder.encode(signupRequest.getPassword()));

        userRepository.save(user);
        user.setProfileUrl(uploadImageFile(signupRequest.getProfileFile(), user));
        String accessToken = TokenProvider.createToken(user);

        return LoginResponse.from(user, accessToken);
    }

   private void checkDuplicateEmail(String email) {
        if (userRepository.existsByEmail(email)) {
            throw new CustomException(UserErrorCode.DUPLICATE_USER_ID);
        }
    }
    
   private void checkConfirmPassword(String password, String passwordCheck) {
        if (!password.equals(passwordCheck)) {
            throw new CustomException(UserErrorCode.NOT_MATCH_PASSWORD_CONFIRM);
        }
    }
    

일반적인 회원가입이다. 한가지 짚어보고 넘어갈 부분은

userRepository.save(user);
user.setProfileUrl(uploadImageFile(signupRequest.getProfileFile(), user));

이 부분

save로 먼저 저장을 하고 저장한 객체에 접근하여 데이터를 변경하여도 DB에 적용이 된다.
이는 JPA의 영속성과 관련된 부분으로 save를 통해 user를 영속성 컨테이너에 저장하여 저장된 영속 엔티티들은 DB와 동일성을 보장해준다.

그 후 로그인 로직을 처리해보도록 하자

먼저 jwt 방식의 토큰 로그인을 구현하기 위해 TokenPorvider 클래스를 생성한다

@Service
public class TokenProvider {

    private static String SECRET_KEY;

    @Value("${secret-key-source}")
    public void setKey(String value) {
        SECRET_KEY = value;
    }

    public static String createToken(User user) {
        Date expiryDate = Date.from(
                Instant.now()
                        .plus(1, ChronoUnit.DAYS)
        );

        Claims claims = Jwts.claims();
        claims.put("userId", user.getId());
        claims.put("userEmail", user.getEmail());

        return Jwts.builder()
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .setClaims(claims)
                .setExpiration(expiryDate)
                .compact();
    }

    // Claims에서 loginId 꺼내기
    public static String getUserEmail(String token) {
        return extractClaims(token).get("userEmail").toString();
    }

    public static Long getUserId(String token) {
        return Long.valueOf(extractClaims(token).get("userId").toString());
    }

    // 밝급된 Token이 만료 시간이 지났는지 체크
    public static boolean isExpired(String token) {
        Date expiredDate = extractClaims(token).getExpiration();
        // Token의 만료 날짜가 지금보다 이전인지 check
        return expiredDate.before(new Date());
    }

    private static Claims extractClaims(String token) {
        return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
    }

}

당연히 시크릿키는 노출되면 안된다.
간단한 코드들만 있으니 서비스에 맞게 커스텀해서 사용하면 된다

profile
안녕하세요 백엔드 개발자를 지망하고있는 노원호라고합니다.

0개의 댓글

관련 채용 정보