#24 simple sns: 로그인 api 구현

This commit is contained in:
haerong22
2022-11-01 00:40:10 +09:00
parent 90dd93838e
commit d165c8d824
8 changed files with 86 additions and 7 deletions

View File

@@ -25,6 +25,11 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.postgresql:postgresql'
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'

View File

@@ -1,8 +1,10 @@
package com.example.sns.controller;
import com.example.sns.controller.request.UserJoinRequest;
import com.example.sns.controller.request.UserLoginRequest;
import com.example.sns.controller.response.Response;
import com.example.sns.controller.response.UserJoinResponse;
import com.example.sns.controller.response.UserLoginResponse;
import com.example.sns.model.User;
import com.example.sns.service.UserService;
import lombok.RequiredArgsConstructor;
@@ -24,4 +26,10 @@ public class UserController {
return Response.success(UserJoinResponse.fromUser(user));
}
@PostMapping("/login")
public Response<UserLoginResponse> login(@RequestBody UserLoginRequest request) {
String token = userService.login(request.getUsername(), request.getPassword());
return Response.success(new UserLoginResponse(token));
}
}

View File

@@ -0,0 +1,11 @@
package com.example.sns.controller.response;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class UserLoginResponse {
private String token;
}

View File

@@ -9,6 +9,8 @@ import org.springframework.http.HttpStatus;
public enum ErrorCode {
DUPLICATED_USER_NAME(HttpStatus.CONFLICT, "Username is duplicated."),
USER_NOT_FOUND(HttpStatus.NOT_FOUND, "User not founded."),
INVALID_PASSWORD(HttpStatus.UNAUTHORIZED, "Password is invalid."),
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "Internal server error.")
;

View File

@@ -12,12 +12,17 @@ public class SnsApplicationException extends RuntimeException {
private ErrorCode errorCode;
private String message;
public SnsApplicationException(ErrorCode errorCode) {
this.errorCode = errorCode;
this.message = null;
}
@Override
public String getMessage() {
if (message==null) {
return errorCode.getMessage();
}
return String.format("$s, $s", errorCode.getMessage(), message);
return String.format("%s, %s", errorCode.getMessage(), message);
}
}

View File

@@ -5,11 +5,15 @@ import com.example.sns.exception.SnsApplicationException;
import com.example.sns.model.User;
import com.example.sns.model.entity.UserEntity;
import com.example.sns.repository.UserEntityRepository;
import com.example.sns.util.JwtTokenUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import static com.example.sns.exception.ErrorCode.*;
@Service
@RequiredArgsConstructor
public class UserService {
@@ -17,12 +21,18 @@ public class UserService {
private final UserEntityRepository userEntityRepository;
private final BCryptPasswordEncoder encoder;
@Value("${jwt.secret-key}")
private String secretKey;
@Value("${jwt.token.expired-time-ms}")
private Long expiredTimeMs;
@Transactional
public User join(String username, String password){
public User join(String username, String password) {
// username 확인
userEntityRepository.findByUsername(username).ifPresent(it -> {
throw new SnsApplicationException(ErrorCode.DUPLICATED_USER_NAME, String.format("%s is duplicated", username));
throw new SnsApplicationException(DUPLICATED_USER_NAME, String.format("%s is duplicated", username));
});
// 회원가입 진행
@@ -34,13 +44,17 @@ public class UserService {
public String login(String username, String password) {
// 회원가입 여부 체크
UserEntity userEntity = userEntityRepository.findByUsername(username).orElseThrow(SnsApplicationException::new);
UserEntity userEntity = userEntityRepository.findByUsername(username)
.orElseThrow(
() -> new SnsApplicationException(USER_NOT_FOUND, String.format("%s not founded", username))
);
// 비밀번호 체크
if (!userEntity.getPassword().equals(password)) {
throw new SnsApplicationException();
if (!encoder.matches(password, userEntity.getPassword())) {
throw new SnsApplicationException(INVALID_PASSWORD);
}
return "";
// 토큰 생성
return JwtTokenUtils.generateToken(username, secretKey, expiredTimeMs);
}
}

View File

@@ -0,0 +1,30 @@
package com.example.sns.util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Date;
public class JwtTokenUtils {
public static String generateToken(String username, String key, long expiredTimeMs) {
Claims claims = Jwts.claims();
claims.put("username", username);
return Jwts.builder()
.setClaims(claims)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + expiredTimeMs))
.signWith(getKey(key), SignatureAlgorithm.HS256)
.compact();
}
private static Key getKey(String key) {
byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
return Keys.hmacShaKeyFor(keyBytes);
}
}

View File

@@ -21,3 +21,7 @@ spring:
platform: postgres
driver-class-name: org.postgresql.Driver
jwt:
secret-key: simple_sns_application_secret_key
token:
expired-time-ms: 2592000000