Skip to content

Commit

Permalink
πŸš€ [Deploy] - μ†Œμ…œ 둜그인 및 ResponseDto 변경사항 반영 (#13)
Browse files Browse the repository at this point in the history
* Feat: customException κ΅¬ν˜„

* Feat: responseDto κ΅¬ν˜„

* Feat: Spring Security, JWT Cookie, μ†Œμ…œ 둜그인 κΈ°λŠ₯ κ΅¬ν˜„

* Feat: Spring Security, JWT Cookie, μ†Œμ…œ 둜그인 κΈ°λŠ₯ κ΅¬ν˜„

* Fix: μ½”λ“œ μ—λŸ¬ μˆ˜μ •

* Refactor: 아직 μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” μ½”λ“œ μ‚­μ œ

* Feat: oauth2 μ˜μ‘΄μ„± μΆ”κ°€

* Chore: Credentials μΆ”κ°€

---------

Co-authored-by: Jang99u <[email protected]>
Co-authored-by: λ―Όμž₯규 <[email protected]>
  • Loading branch information
3 people committed May 6, 2024
1 parent 5237ca3 commit 0985de4
Show file tree
Hide file tree
Showing 44 changed files with 1,520 additions and 3 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ dependencies {
// spring security
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation 'org.springframework.security:spring-security-test'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'

// spring boot
implementation 'org.springframework.boot:spring-boot-starter-web'
Expand Down
2 changes: 1 addition & 1 deletion spot-server-properties
11 changes: 11 additions & 0 deletions src/main/java/ice/spot/annotation/UserId.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package ice.spot.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserId {
}
33 changes: 33 additions & 0 deletions src/main/java/ice/spot/config/WebMVCConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package ice.spot.config;

import ice.spot.constant.Constants;
import ice.spot.interceptor.pre.UserIdArgumentResolver;
import ice.spot.interceptor.pre.UserIdInterceptor;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class WebMVCConfig implements WebMvcConfigurer {
private final UserIdArgumentResolver userIdArgumentResolver;

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
WebMvcConfigurer.super.addArgumentResolvers(resolvers);
resolvers.add(this.userIdArgumentResolver);
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new UserIdInterceptor())
.addPathPatterns("/**")
.excludePathPatterns(Constants.NO_NEED_AUTH);
}
}
16 changes: 16 additions & 0 deletions src/main/java/ice/spot/constant/Constants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ice.spot.constant;

import java.util.List;

public class Constants {
public static String CLAIM_USER_ID = "uuid";
public static String CLAIM_USER_ROLE = "role";
public static String PREFIX_BEARER = "Bearer ";
public static String PREFIX_AUTH = "authorization";
public static String ACCESS_COOKIE_NAME = "access_token";
public static String REFRESH_COOKIE_NAME = "refresh_token";
public static List<String> NO_NEED_AUTH = List.of(
"/api/auth/sign-up",
"/api/auth/sign-in"
);
}
27 changes: 27 additions & 0 deletions src/main/java/ice/spot/controller/AuthController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package ice.spot.controller;

import ice.spot.annotation.UserId;
import ice.spot.dto.global.ResponseDto;
import ice.spot.dto.request.OauthSignUpDto;
import ice.spot.service.AuthService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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;

@Slf4j
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class AuthController {

private final AuthService authService;

@PostMapping("/oauth2/sign-up")
public ResponseDto<?> signUp(@UserId Long userId, @RequestBody OauthSignUpDto oauthSignUpDto) {
authService.signUp(userId, oauthSignUpDto);
return ResponseDto.ok(null);
}
}
33 changes: 31 additions & 2 deletions src/main/java/ice/spot/domain/User.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
package ice.spot.domain;

import ice.spot.dto.type.EProvider;
import ice.spot.dto.type.ERole;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.DynamicUpdate;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "user")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@DynamicUpdate
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Expand All @@ -31,17 +36,41 @@ public class User {
@Column(name = "point")
private Long point;

@Column(name = "role", nullable = false)
@Enumerated(EnumType.STRING)
private ERole role;

@Column(name = "provider", nullable = false)
@Enumerated(EnumType.STRING)
private EProvider provider;

@Column(name = "created_at")
private LocalDate createdAt;

@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<BoardingRecord> boardingRecords = new ArrayList<>();

public User(String serialId, String password, String nickname, Long point) {
@Column(name = "refresh_token")
private String refreshToken;

@Builder
public User(String serialId, String password, String nickname, ERole role, EProvider provider, Long point) {
this.serialId = serialId;
this.password = password;
this.nickname = nickname;
this.role = role;
this.provider = provider;
this.point = point;
this.createdAt = LocalDate.now();
}

public void register(String nickname) {
this.nickname = nickname;
this.createdAt = LocalDate.now();
this.role = ERole.USER;
}

public void updateRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
}
16 changes: 16 additions & 0 deletions src/main/java/ice/spot/dto/global/ExceptionDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ice.spot.dto.global;

import ice.spot.exeption.ErrorCode;

public record ExceptionDto(
Integer code,
String message
) {
public ExceptionDto(ErrorCode errorCode) {
this(errorCode.getCode(), errorCode.getMessage());
}

public static ExceptionDto of(ErrorCode errorCode) {
return new ExceptionDto(errorCode);
}
}
60 changes: 60 additions & 0 deletions src/main/java/ice/spot/dto/global/ResponseDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package ice.spot.dto.global;

import ice.spot.exeption.CommonException;
import ice.spot.exeption.ErrorCode;
import jakarta.annotation.Nullable;
import jakarta.validation.constraints.NotNull;
import net.minidev.json.annotate.JsonIgnore;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

public record ResponseDto<T> (
@JsonIgnore HttpStatus httpStatus,
boolean success,
@Nullable T data,
@Nullable ExceptionDto exceptionDto
) {
public static <T> ResponseDto<T> ok(T data){
return new ResponseDto<>(
HttpStatus.OK,
true,
data,
null
);
}
public static ResponseDto<Boolean> created(Boolean data){
return new ResponseDto<>(
HttpStatus.CREATED,
true,
data,
null
);
}
public static ResponseDto<?> fail(@NotNull CommonException e){
return new ResponseDto<>(
e.getErrorCode().getHttpStatus(),
false,
null,
new ExceptionDto(e.getErrorCode())
);
}

public static ResponseDto<?> fail(final MissingServletRequestParameterException e) {
return new ResponseDto<>(
HttpStatus.BAD_REQUEST,
false,
null,
new ExceptionDto(ErrorCode.MISSING_REQUEST_PARAMETER)
);
}

public static ResponseDto<?> fail(final MethodArgumentTypeMismatchException e) {
return new ResponseDto<>(
HttpStatus.INTERNAL_SERVER_ERROR,
false,
null,
new ExceptionDto(ErrorCode.INVALID_PARAMETER_FORMAT)
);
}
}
9 changes: 9 additions & 0 deletions src/main/java/ice/spot/dto/request/OauthSignUpDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package ice.spot.dto.request;

import com.fasterxml.jackson.annotation.JsonProperty;

public record OauthSignUpDto(
@JsonProperty("nickname")
String nickname
) {
}
18 changes: 18 additions & 0 deletions src/main/java/ice/spot/dto/response/JwtTokenDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package ice.spot.dto.response;

import lombok.Builder;

import java.io.Serializable;

@Builder
public record JwtTokenDto(
String accessToken,
String refreshToken
) implements Serializable {
public static JwtTokenDto of(String accessToken, String refreshToken) {
return JwtTokenDto.builder()
.accessToken(accessToken)
.refreshToken(refreshToken)
.build();
}
}
13 changes: 13 additions & 0 deletions src/main/java/ice/spot/dto/type/EProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package ice.spot.dto.type;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum EProvider {

KAKAO("KAKAO");

private final String name;
}
16 changes: 16 additions & 0 deletions src/main/java/ice/spot/dto/type/ERole.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ice.spot.dto.type;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum ERole {

GUEST("GUEST", "ROLE_GUEST"),
USER("USER", "ROLE_USER"),
ADMIN("ADMIN", "ROLE_ADMIN");

private final String role;
private final String securityRole;
}
11 changes: 11 additions & 0 deletions src/main/java/ice/spot/exeption/CommonException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package ice.spot.exeption;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public class CommonException extends RuntimeException {
private final ErrorCode errorCode;
public String getMessage() { return this.errorCode.getMessage(); }
}
40 changes: 40 additions & 0 deletions src/main/java/ice/spot/exeption/ErrorCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package ice.spot.exeption;

import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
@AllArgsConstructor
public enum ErrorCode {
//400
WRONG_ENTRY_POINT(40000, HttpStatus.BAD_REQUEST, "잘λͺ»λœ μ ‘κ·Όμž…λ‹ˆλ‹€"),
MISSING_REQUEST_PARAMETER(40001, HttpStatus.BAD_REQUEST, "ν•„μˆ˜ μš”μ²­ νŒŒλΌλ―Έν„°κ°€ λˆ„λ½λ˜μ—ˆμŠ΅λ‹ˆλ‹€."),
INVALID_PARAMETER_FORMAT(40002, HttpStatus.BAD_REQUEST, "μš”μ²­μ— μœ νš¨ν•˜μ§€ μ•Šμ€ 인자 ν˜•μ‹μž…λ‹ˆλ‹€."),
BAD_REQUEST_JSON(40003, HttpStatus.BAD_REQUEST, "잘λͺ»λœ JSON ν˜•μ‹μž…λ‹ˆλ‹€."),

//401
INVALID_HEADER_VALUE(40100, HttpStatus.UNAUTHORIZED, "μ˜¬λ°”λ₯΄μ§€ μ•Šμ€ ν—€λ”κ°’μž…λ‹ˆλ‹€."),
EXPIRED_TOKEN_ERROR(40101, HttpStatus.UNAUTHORIZED, "만료된 ν† ν°μž…λ‹ˆλ‹€."),
INVALID_TOKEN_ERROR(40102, HttpStatus.UNAUTHORIZED, "μœ νš¨ν•˜μ§€ μ•Šμ€ ν† ν°μž…λ‹ˆλ‹€."),
TOKEN_MALFORMED_ERROR(40103, HttpStatus.UNAUTHORIZED, "토큰이 μ˜¬λ°”λ₯΄μ§€ μ•ŠμŠ΅λ‹ˆλ‹€."),
TOKEN_TYPE_ERROR(40104, HttpStatus.UNAUTHORIZED, "토큰 νƒ€μž…μ΄ μΌμΉ˜ν•˜μ§€ μ•Šκ±°λ‚˜ λΉ„μ–΄μžˆμŠ΅λ‹ˆλ‹€."),
TOKEN_UNSUPPORTED_ERROR(40105, HttpStatus.UNAUTHORIZED, "μ§€μ›ν•˜μ§€μ•ŠλŠ” ν† ν°μž…λ‹ˆλ‹€."),
TOKEN_GENERATION_ERROR(40106, HttpStatus.UNAUTHORIZED, "토큰 생성에 μ‹€νŒ¨ν•˜μ˜€μŠ΅λ‹ˆλ‹€."),
TOKEN_UNKNOWN_ERROR(40107, HttpStatus.UNAUTHORIZED, "μ•Œ 수 μ—†λŠ” ν† ν°μž…λ‹ˆλ‹€."),
LOGIN_FAILURE(40108, HttpStatus.UNAUTHORIZED, "λ‘œκ·ΈμΈμ— μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€"),

//403
FORBIDDEN_ROLE(40300, HttpStatus.FORBIDDEN, "κΆŒν•œμ΄ μ‘΄μž¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€."),

//404
NOT_FOUND_USER(40400, HttpStatus.NOT_FOUND, "μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” μ‚¬μš©μžμž…λ‹ˆλ‹€."),

//500
INTERNAL_SERVER_ERROR(50000, HttpStatus.INTERNAL_SERVER_ERROR, "μ„œλ²„ λ‚΄λΆ€ 였λ₯˜μž…λ‹ˆλ‹€"),
;

private final Integer code;
private final HttpStatus httpStatus;
private final String message;
}
Loading

0 comments on commit 0985de4

Please sign in to comment.