Skip to content

Commit

Permalink
#3 feat: 로그인 API
Browse files Browse the repository at this point in the history
  • Loading branch information
sojungpp committed Dec 9, 2023
1 parent 44b8318 commit a330d5b
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public static <T> BaseResponse<T> OK(@Nullable T data) {
}

public static BaseResponse error(BaseResponseCode baseResponseCode, String message) {
return new BaseResponse<>(baseResponseCode.getStatus().value(), baseResponseCode.getCode(), baseResponseCode.getMessage());
return new BaseResponse<>(baseResponseCode.getStatus().value(), baseResponseCode.getCode(), message);
}

}
24 changes: 24 additions & 0 deletions src/main/java/com/s1350/sooljangmacha/global/utils/JwtUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Date;

import static com.s1350.sooljangmacha.global.Constants.BEARER_PREFIX;
import static com.s1350.sooljangmacha.global.Constants.CLAIM_NAME;
Expand All @@ -19,6 +20,8 @@ public class JwtUtil {
@Value("${jwt.secret}")
private String jwtSecret;

private final long accessTokenExpiryTime = 1000L * 60 * 60 * 24 * 14; // 2주

public static String replaceBearer(String header) {
return header.substring(BEARER_PREFIX.length());
}
Expand Down Expand Up @@ -57,4 +60,25 @@ private Claims getBody(String token) {
return e.getClaims();
}
}

public String issuedAccessToken(Long userId) {
return issuedToken("access_token", accessTokenExpiryTime, String.valueOf(userId));
}

public String issuedToken(String tokenName, long expiryTime, String userId) {
final Date now = new Date();

final Claims claims = Jwts.claims()
.setSubject(tokenName)
.setIssuedAt(now)
.setExpiration(new Date(now.getTime() + expiryTime));

claims.put(CLAIM_NAME, userId);

return Jwts.builder()
.setHeaderParam(Header.TYPE, Header.JWT_TYPE)
.setClaims(claims)
.signWith(getSigningKey())
.compact();
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
package com.s1350.sooljangmacha.user.controller;

import com.s1350.sooljangmacha.global.dto.BaseResponse;
import com.s1350.sooljangmacha.user.dto.request.LoginReq;
import com.s1350.sooljangmacha.user.dto.response.LoginRes;
import com.s1350.sooljangmacha.user.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

@Tag(name = "users", description = "유저 API")
@RestController
Expand All @@ -13,8 +26,17 @@
public class UserController {
private final UserService userService;

// @Operation(summary = "로그인", description = "")
// @PostMapping("/login")
@Operation(summary = "로그인", description = "로그인을 한다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "(S0001)요청에 성공했습니다."),
@ApiResponse(responseCode = "400", description = "(E0001)잘못된 요청입니다. <br> (E0001)이메일을 입력해 주세요. <br> (E0001)provider를 입력해 주세요. <br> (E0001)올바른 이메일 형식으로 입력해 주세요. <br> (E0001)잘못된 provider 값 입니다. <br>", content = @Content(schema = @Schema(implementation = BaseResponse.class))),
@ApiResponse(responseCode = "404", description = "(U0001)존재하지 않는 유저입니다.", content = @Content(schema = @Schema(implementation = BaseResponse.class))),
})
@PostMapping("/login")
public BaseResponse<LoginRes> login(@RequestBody @Valid LoginReq loginReq) {
return BaseResponse.OK(userService.login(loginReq));
}


// @Operation(summary = "로그아웃", description = "")
// @PostMapping("/logout")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.s1350.sooljangmacha.user.dto.request;

import com.s1350.sooljangmacha.global.resolver.EnumValid;
import com.s1350.sooljangmacha.user.entity.Provider;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;

@Data
@NoArgsConstructor
public class LoginReq {

@Schema(type = "String", description = "유저 이메일", example = "ex@naver.com", required = true)
@NotBlank(message = "이메일을 입력해 주세요.")
@Email(message = "올바른 이메일 형식으로 입력해 주세요.")
private String email;

@Schema(type = "String", description = "유저 로그인 종류", example = "KAKAO", allowableValues = {"KAKAO", "APPLE"}, required = true)
@NotBlank(message = "provider를 입력해 주세요.")
@EnumValid(enumClass = Provider.class, ignoreCase = true, message = "잘못된 provider 값 입니다.")
private String provider;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.s1350.sooljangmacha.user.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class LoginRes {

@Schema(type = "String", description = "액세스 토큰")
private String accessToken;

public static LoginRes toEntity(String accessToken) {
return LoginRes.builder()
.accessToken(accessToken)
.build();
}
}
4 changes: 4 additions & 0 deletions src/main/java/com/s1350/sooljangmacha/user/entity/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ public class User extends BaseEntity {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@NotNull
@Size(max = 255)
private String email;

@NotNull
@Size(max = 30)
private String nickname;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.s1350.sooljangmacha.user.repository;

import com.s1350.sooljangmacha.user.entity.Provider;
import com.s1350.sooljangmacha.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByIdAndIsEnable(Long id, boolean isEnable);

Optional<User> findByEmailAndProviderAndIsEnable(String email, Provider provider, boolean isEnable);
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
package com.s1350.sooljangmacha.user.service;


import com.s1350.sooljangmacha.global.exception.BaseException;
import com.s1350.sooljangmacha.global.exception.BaseResponseCode;
import com.s1350.sooljangmacha.global.utils.JwtUtil;
import com.s1350.sooljangmacha.user.dto.request.LoginReq;
import com.s1350.sooljangmacha.user.dto.response.LoginRes;
import com.s1350.sooljangmacha.user.entity.Provider;
import com.s1350.sooljangmacha.user.entity.User;
import com.s1350.sooljangmacha.user.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;


@Service
@RequiredArgsConstructor
public class UserService {
private UserRepository userRepository;
private final UserRepository userRepository;
private final JwtUtil jwtUtil;

// 로그인
public LoginRes login(LoginReq request) {
User user = userRepository.findByEmailAndProviderAndIsEnable(request.getEmail(), Provider.valueOf(request.getProvider()), true)
.orElseThrow(() -> new BaseException(BaseResponseCode.USER_NOT_FOUND));
return LoginRes.toEntity(jwtUtil.issuedAccessToken(user.getId()));
}

// 로그아웃

Expand Down

0 comments on commit a330d5b

Please sign in to comment.