Skip to content

Commit

Permalink
Merge pull request #14 from 9oormthonUniv-seoultech/develop
Browse files Browse the repository at this point in the history
Develop to Main #1
  • Loading branch information
Jeongh00 authored Sep 9, 2024
2 parents 3bcfa61 + 4222204 commit 779e0f8
Show file tree
Hide file tree
Showing 71 changed files with 1,644 additions and 44 deletions.
9 changes: 8 additions & 1 deletion .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Backend CD # actions 이름

on:
push:
branches: [ main ]
branches: [ develop ]

jobs:
deploy:
Expand All @@ -24,6 +24,13 @@ jobs:
echo "${{ secrets.APPLICATION_PROD }}" > ./application-prod.yml
shell: bash

- name: make application-oauth yml file
run: |
cd ./outbound/src/main/resources
touch ./application-oauth.yml
echo "${{ secrets.APPLICATION_OAUTH }}" > ./application-oauth.yml
shell: bash

- name: Gradlew 권한 부여
run: chmod +x ./gradlew

Expand Down
4 changes: 3 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ subprojects {
annotationProcessor "jakarta.persistence:jakarta.persistence-api"

implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2' // swagger
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' // s3

testImplementation 'org.springframework.boot:spring-boot-starter-test'

Expand All @@ -49,6 +48,9 @@ subprojects {

implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'com.fasterxml.jackson.core:jackson-databind'

// AWS S3
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
}

test {
Expand Down
7 changes: 2 additions & 5 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,9 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

testImplementation 'io.rest-assured:rest-assured'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2' // swagger

// Jwt
implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
implementation 'io.jsonwebtoken:jjwt-impl:0.12.3'
implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3'
testImplementation 'io.rest-assured:rest-assured'
}

bootJar {
Expand Down
28 changes: 28 additions & 0 deletions core/src/main/java/com/pocket/core/config/SwaggerConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.pocket.core.config;

import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import lombok.RequiredArgsConstructor;
import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@OpenAPIDefinition(
info = @io.swagger.v3.oas.annotations.info.Info(
title = "POCKET 4 CUT API 명세서",
description = "POCKET 4 CUT BE API 명세서입니다.",
version = "v1")
)
@RequiredArgsConstructor
@Configuration
public class SwaggerConfig {

@Bean
public GroupedOpenApi stOpenApi() {

return GroupedOpenApi.builder()
.group("POCKET 4 CUT API v1")
.pathsToMatch("/**")
.build();
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.pocket.core.exception.common;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NonNull;
import org.springframework.http.HttpStatus;

@Getter
@AllArgsConstructor
@JsonPropertyOrder({"statusCode", "message", "content"})
public class ApiResponse<T> {

@JsonProperty("statusCode")
@NonNull
private final String statusCode;

@JsonProperty("message")
@NonNull
private final String message;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonProperty("content")
private T content;

// 성공한 경우 응답 생성
public static <T> ApiResponse<T> onSuccess(T content) {
return new ApiResponse<>(HttpStatus.OK.name(), HttpStatus.OK.getReasonPhrase(), content);
}

// 실패한 경우 응답 생성
public static <T> ApiResponse<T> onFailure(String statusCode, String message) {
return new ApiResponse<>(statusCode, message, null);
}

public static <T> ApiResponse<T> onFailure(String statusCode, String message, T content) {
return new ApiResponse<>(statusCode, message, content);
}

// Json serialize
public String toJsonString() throws JsonProcessingException {
return new ObjectMapper().writeValueAsString(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package com.pocket.core.exception.common;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.jackson.Jacksonized;
import org.springframework.http.HttpStatus;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Jacksonized
public class ApplicationResponse<T> {
private ApplicationResult result;
private T payload;

public static <T> ApplicationResponse<T> ok(T payload) {
return ApplicationResponse.<T>builder()
.result(ApplicationResult.builder()
.code(HttpStatus.OK.value())
.message("API 호출 성공")
.build())
.payload(payload)
.build();
}

public static <T> ApplicationResponse<T> ok(T payload, String message) {
return ApplicationResponse.<T>builder()
.result(ApplicationResult.builder()
.code(HttpStatus.OK.value())
.message(message)
.build())
.payload(payload)
.build();
}

public static <T> ApplicationResponse<T> badRequest(T payload) {
return ApplicationResponse.<T>builder()
.result(ApplicationResult.builder()
.code(HttpStatus.BAD_REQUEST.value())
.message("잘못된 요청입니다.")
.build())
.payload(payload)
.build();
}

public static <T> ApplicationResponse<T> badRequest(T payload, String message) {
return ApplicationResponse.<T>builder()
.result(ApplicationResult.builder()
.code(HttpStatus.BAD_REQUEST.value())
.message(message)
.build())
.payload(payload)
.build();
}

public static <T> ApplicationResponse<T> notAuthenticated(T payload) {
return ApplicationResponse.<T>builder()
.result(ApplicationResult.builder()
.code(HttpStatus.UNAUTHORIZED.value())
.message("잘못된 접근입니다.")
.build())
.payload(payload)
.build();
}

public static <T> ApplicationResponse<T> notAuthenticated(T payload, String message) {
return ApplicationResponse.<T>builder()
.result(ApplicationResult.builder()
.code(HttpStatus.UNAUTHORIZED.value())
.message(message)
.build())
.payload(payload)
.build();
}

public static <T> ApplicationResponse<T> server(T payload) {
return ApplicationResponse.<T>builder()
.result(ApplicationResult.builder()
.code(HttpStatus.INTERNAL_SERVER_ERROR.value())
.message("API 호출 실패")
.build())
.payload(payload)
.build();
}

public static <T> ApplicationResponse<T> server(T payload, String message) {
return ApplicationResponse.<T>builder()
.result(ApplicationResult.builder()
.code(HttpStatus.INTERNAL_SERVER_ERROR.value())
.message(message)
.build())
.payload(payload)
.build();
}

public static <T> ApplicationResponse<T> custom(T payload, Integer code, String message) {
return ApplicationResponse.<T>builder()
.result(ApplicationResult.builder()
.code(code)
.message(message)
.build())
.payload(payload)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.pocket.core.exception.common;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.jackson.Jacksonized;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Jacksonized
public class ApplicationResult {
private Integer code;
private String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.pocket.core.exception.common;

import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity {

@CreatedDate
private LocalDateTime createdAt;

@LastModifiedDate
protected LocalDateTime updatedAt;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.pocket.core.exception.common;

import org.springframework.http.HttpStatus;

public interface BaseErrorCode {

HttpStatus getHttpStatus();

String getCode();

String getMessage();

ApiResponse<Void> getErrorResponse();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.pocket.core.exception.common;

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

@Getter
@AllArgsConstructor
public enum GlobalErrorCode implements BaseErrorCode {
VALIDATION_FAILED(HttpStatus.BAD_REQUEST, "ERROR4000", "입력값에 대한 검증에 실패했습니다."),
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "ERROR5000", "서버에 문제가 발생했습니다. 잠시 후 다시 시도해주세요.");

private final HttpStatus httpStatus;
private final String code;
private final String message;

@Override
public ApiResponse<Void> getErrorResponse() {
return ApiResponse.onFailure(code, message);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.pocket.core.exception.jwt;

import com.pocket.core.util.HttpResponseUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
* 인증된 사용자가 필요한 권한없이 접근하려고 할 때 발생하는 예외 처리
*/
@Slf4j
@Component
public class JwtAccessDeniedHandler implements AccessDeniedHandler {

@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException {
log.warn("Access Denied: ", accessDeniedException);

HttpResponseUtil.setErrorResponse(response, HttpStatus.FORBIDDEN,
SecurityErrorCode.FORBIDDEN.getErrorResponse());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.pocket.core.exception.jwt;

import com.pocket.core.exception.common.ApiResponse;
import com.pocket.core.util.HttpResponseUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
* 사용자가 인증되지 않은 상태에서 접근하려고 할 때 발생하는 예외 처리
*/
@Slf4j
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {

@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException)
throws IOException {
HttpStatus httpStatus;
ApiResponse<String> errorResponse;

log.error(">>>>>> AuthenticationException: ", authException);
httpStatus = HttpStatus.UNAUTHORIZED;
errorResponse = ApiResponse.onFailure(
SecurityErrorCode.UNAUTHORIZED.getCode(),
SecurityErrorCode.UNAUTHORIZED.getMessage(),
authException.getMessage());

HttpResponseUtil.setErrorResponse(response, httpStatus, errorResponse);
}
}
Loading

0 comments on commit 779e0f8

Please sign in to comment.