From d165c8d8243f0805b237ea6f5a9d14ffd9a7c871 Mon Sep 17 00:00:00 2001 From: haerong22 Date: Tue, 1 Nov 2022 00:40:10 +0900 Subject: [PATCH] =?UTF-8?q?#24=20simple=20sns:=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20api=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple_sns/build.gradle | 5 ++++ .../sns/controller/UserController.java | 8 +++++ .../response/UserLoginResponse.java | 11 +++++++ .../com/example/sns/exception/ErrorCode.java | 2 ++ .../exception/SnsApplicationException.java | 7 ++++- .../com/example/sns/service/UserService.java | 26 ++++++++++++---- .../com/example/sns/util/JwtTokenUtils.java | 30 +++++++++++++++++++ simple_sns/src/main/resources/application.yml | 4 +++ 8 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 simple_sns/src/main/java/com/example/sns/controller/response/UserLoginResponse.java create mode 100644 simple_sns/src/main/java/com/example/sns/util/JwtTokenUtils.java diff --git a/simple_sns/build.gradle b/simple_sns/build.gradle index a9cdd81e..417036e3 100644 --- a/simple_sns/build.gradle +++ b/simple_sns/build.gradle @@ -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' diff --git a/simple_sns/src/main/java/com/example/sns/controller/UserController.java b/simple_sns/src/main/java/com/example/sns/controller/UserController.java index db976256..7dd0b9e4 100644 --- a/simple_sns/src/main/java/com/example/sns/controller/UserController.java +++ b/simple_sns/src/main/java/com/example/sns/controller/UserController.java @@ -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 login(@RequestBody UserLoginRequest request) { + String token = userService.login(request.getUsername(), request.getPassword()); + return Response.success(new UserLoginResponse(token)); + } } diff --git a/simple_sns/src/main/java/com/example/sns/controller/response/UserLoginResponse.java b/simple_sns/src/main/java/com/example/sns/controller/response/UserLoginResponse.java new file mode 100644 index 00000000..d749c665 --- /dev/null +++ b/simple_sns/src/main/java/com/example/sns/controller/response/UserLoginResponse.java @@ -0,0 +1,11 @@ +package com.example.sns.controller.response; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class UserLoginResponse { + + private String token; +} diff --git a/simple_sns/src/main/java/com/example/sns/exception/ErrorCode.java b/simple_sns/src/main/java/com/example/sns/exception/ErrorCode.java index bbaa0a0b..1b3a5678 100644 --- a/simple_sns/src/main/java/com/example/sns/exception/ErrorCode.java +++ b/simple_sns/src/main/java/com/example/sns/exception/ErrorCode.java @@ -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.") ; diff --git a/simple_sns/src/main/java/com/example/sns/exception/SnsApplicationException.java b/simple_sns/src/main/java/com/example/sns/exception/SnsApplicationException.java index 50a28d2c..7012c970 100644 --- a/simple_sns/src/main/java/com/example/sns/exception/SnsApplicationException.java +++ b/simple_sns/src/main/java/com/example/sns/exception/SnsApplicationException.java @@ -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); } } diff --git a/simple_sns/src/main/java/com/example/sns/service/UserService.java b/simple_sns/src/main/java/com/example/sns/service/UserService.java index a8a019cf..db913ab2 100644 --- a/simple_sns/src/main/java/com/example/sns/service/UserService.java +++ b/simple_sns/src/main/java/com/example/sns/service/UserService.java @@ -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); } } diff --git a/simple_sns/src/main/java/com/example/sns/util/JwtTokenUtils.java b/simple_sns/src/main/java/com/example/sns/util/JwtTokenUtils.java new file mode 100644 index 00000000..6e8754f9 --- /dev/null +++ b/simple_sns/src/main/java/com/example/sns/util/JwtTokenUtils.java @@ -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); + } +} diff --git a/simple_sns/src/main/resources/application.yml b/simple_sns/src/main/resources/application.yml index c1794ed9..9d35ee7a 100644 --- a/simple_sns/src/main/resources/application.yml +++ b/simple_sns/src/main/resources/application.yml @@ -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 \ No newline at end of file