Skip to content

Commit

Permalink
Merge pull request #332 from twenty-three-23/dev
Browse files Browse the repository at this point in the history
V 1.1.0 배포
  • Loading branch information
snacktime81 authored Aug 20, 2024
2 parents f97fbc8 + 13b759c commit bfd2c35
Show file tree
Hide file tree
Showing 104 changed files with 2,364 additions and 145 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/cd_prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,18 @@ jobs:
logging.config: classpath:spring-logback.xml
gpt.api.key: ${{secrets.GPT_API_KEY_PROD}}
jwt.secret.key: ${{secrets.JWT_SECRET_KEY_PROD}}
jwt.access.key: ${{secrets.JWT_ACCESS_KEY}}
jwt.refresh.key: ${{secrets.JWT_REFRESH_KEY}}
spring.sql.init.mode: ${{ secrets.DATA_SQL_OPTION_PROD }}
spring.jpa.defer-datasource-initialization: ${{ secrets.DATA_INITALIZATION_OPTION_PROD }}
clova.speech-api.secret: ${{ secrets.CLOVA_SPEECH_SECRET_KEY_PROD }}
clova.speech-api.url: ${{ secrets.CLOVA_SPEECH_URL_PROD }}
clova.divide-sentence-api.key: ${{ secrets.CLOVASTUDIO_API_KEY_PROD }}
clova.divide-sentence-api.gw-key: ${{ secrets.CLOVASTUDIO_APIGW_API_KEY_PROD }}
clova.divide-sentence-api.url: ${{ secrets.CLOVASTUDIO_API_URL_PROD }}
sentry.dsn: ${{ secrets.SENTRY_DSN_PROD }}
app.version: ${{ secrets.APP_VERSION_PROD}}
app.available: ${{ secrets.APP_AVAILABLE_PROD}}

# application.yml 파일 내용 확인
- name: Display modified application.yml
Expand Down Expand Up @@ -91,6 +96,7 @@ jobs:
run: |
ssh -o StrictHostKeyChecking=no -o ServerAliveInterval=60 -o ServerAliveCountMax=2 ubuntu@${{ secrets.PROD_EC2_IP }} << 'EOF'
export SENTRY_DSN="${{ secrets.SENTRY_DSN_DEV }}"
echo "${{ secrets.DOCKERHUB_PASSWORD_PROD }}" | sudo docker login -u ${{ secrets.DOCKERHUB_USERNAME_PROD }} --password-stdin
sudo docker pull ${{ secrets.DOCKERHUB_USERNAME_PROD }}/github-actions-demo
sudo docker stop $(sudo docker ps -q) 2>/dev/null || true
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/ci_prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,19 @@ jobs:
logging.config: classpath:spring-logback.xml
gpt.api.key: ${{secrets.GPT_API_KEY_PROD}}
jwt.secret.key: ${{secrets.JWT_SECRET_KEY_PROD}}
jwt.access.key: ${{secrets.JWT_ACCESS_KEY}}
jwt.refresh.key: ${{secrets.JWT_REFRESH_KEY}}
spring.sql.init.mode: ${{ secrets.DATA_SQL_OPTION_PROD }}
spring.jpa.defer-datasource-initialization: ${{ secrets.DATA_INITALIZATION_OPTION_PROD }}
clova.speech-api.secret: ${{ secrets.CLOVA_SPEECH_SECRET_KEY_PROD }}
clova.speech-api.url: ${{ secrets.CLOVA_SPEECH_URL_PROD }}
clova.divide-sentence-api.key: ${{ secrets.CLOVASTUDIO_API_KEY_PROD }}
clova.divide-sentence-api.gw-key: ${{ secrets.CLOVASTUDIO_APIGW_API_KEY_PROD }}
clova.divide-sentence-api.url: ${{ secrets.CLOVASTUDIO_API_URL_PROD }}
sentry.dsn: ${{ secrets.SENTRY_DSN_PROD }}
app.version: ${{ secrets.APP_VERSION_PROD}}
app.available: ${{ secrets.APP_AVAILABLE_PROD}}


# application.yml 파일 내용 확인
- name: Display modified application.yml
Expand Down
9 changes: 8 additions & 1 deletion .github/workflows/cicd_dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,20 @@ jobs:
logging.config: classpath:spring-logback.xml
gpt.api.key: ${{secrets.GPT_API_KEY}}
jwt.secret.key: ${{secrets.JWT_SECRET_KEY}}
jwt.access.key: ${{secrets.JWT_ACCESS_KEY}}
jwt.refresh.key: ${{secrets.JWT_REFRESH_KEY}}
spring.sql.init.mode: ${{ secrets.DATA_SQL_OPTION }}
spring.jpa.defer-datasource-initialization: ${{ secrets.DATA_INITALIZATION_OPTION }}
clova.speech-api.secret: ${{ secrets.CLOVA_SPEECH_SECRET_KEY }}
clova.speech-api.url: ${{ secrets.CLOVA_SPEECH_URL }}
clova.divide-sentence-api.key: ${{ secrets.CLOVASTUDIO_API_KEY }}
clova.divide-sentence-api.gw-key: ${{ secrets.CLOVASTUDIO_APIGW_API_KEY }}
clova.divide-sentence-api.url: ${{ secrets.CLOVASTUDIO_API_URL }}

sentry.dsn: ${{ secrets.SENTRY_DSN_DEV }}
app.version: ${{ secrets.APP_VERSION_DEV}}
app.available: ${{ secrets.APP_AVAILABLE_DEV}}


# application.yml 파일 내용 확인
- name: Display modified application.yml
run: cat ${{ env.RESOURCE_PATH }}
Expand Down Expand Up @@ -92,6 +98,7 @@ jobs:
run: |
ssh -o StrictHostKeyChecking=no -o ServerAliveInterval=60 ubuntu@${{ secrets.DEV_EC2_IP }} << 'EOF'
export SENTRY_DSN="${{ secrets.SENTRY_DSN_DEV }}"
echo "${{ secrets.DOCKERHUB_PASSWORD }}" | sudo docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin
sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/github-actions-demo
sudo docker stop $(sudo docker ps -q) 2>/dev/null || true
Expand Down
18 changes: 18 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
id 'java'
id 'org.springframework.boot' version '3.3.0'
id 'io.spring.dependency-management' version '1.1.5'
id "io.sentry.jvm.gradle" version "4.10.0"
}

group = 'com.twentyThree'
Expand All @@ -23,6 +24,17 @@ repositories {
mavenCentral()
}

ext {
set('springCloudVersion', "2023.0.1")
}

dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}


dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
compileOnly 'org.projectlombok:lombok'
Expand Down Expand Up @@ -53,6 +65,9 @@ dependencies {
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

//spring-security
implementation 'org.springframework.boot:spring-boot-starter-security'

//java JWT
implementation 'io.jsonwebtoken:jjwt-api:0.12.6'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.6'
Expand All @@ -65,6 +80,9 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webflux'
runtimeOnly("io.netty:netty-resolver-dns-native-macos:4.2.0.Alpha1:osx-aarch_64")

//FeignClinet
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'

//Tika
implementation 'org.apache.tika:tika-core:2.4.1'
implementation 'org.apache.tika:tika-parsers-standard-package:2.4.1'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import java.util.List;

@Deprecated
@RequiredArgsConstructor
@Configuration
public class ArgumentResolverConfig implements WebMvcConfigurer {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.twentythree.peech.auth.controller;

import com.twentythree.peech.auth.service.ReissueAccessAndRefreshTokenService;
import com.twentythree.peech.user.dto.AccessAndRefreshToken;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
public class AuthController {

private final ReissueAccessAndRefreshTokenService reissueAccessAndRefreshTokenService;

@PostMapping("api/v1.1/auth/reissue")
public AccessAndRefreshToken reissueAccessToken(String refreshToken) {
return reissueAccessAndRefreshTokenService.createNewToken(refreshToken);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.twentythree.peech.auth.controller;

import com.twentythree.peech.user.dto.AccessAndRefreshToken;
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 org.springframework.web.bind.annotation.RequestBody;

public interface SwaggerAuthController {
@ApiResponse(responseCode = "200", description = "성공", content = {@Content(schema = @Schema(implementation = AccessAndRefreshToken.class), mediaType = "application/json")})
@ApiResponse(responseCode = "401", description = "실패", content = {@Content(schema = @Schema(implementation = Error.class), mediaType = "application/json")})
AccessAndRefreshToken reissueAccessToken(@RequestBody String refreshToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Deprecated
public @interface LoginUserId {
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.twentythree.peech.auth.dto;


@Deprecated
public record UserIdDTO(Long userId) {
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package com.twentythree.peech.auth.interceptor;

import com.twentythree.peech.common.exception.UserAlreadyExistException;
import com.twentythree.peech.common.utils.JWTUtils;
import io.jsonwebtoken.JwtException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

@Deprecated
@RequiredArgsConstructor
public class AuthInterceptor implements HandlerInterceptor {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

@Deprecated
@Slf4j
@RequiredArgsConstructor
public class AuthArgumentResolver implements HandlerMethodArgumentResolver {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.twentythree.peech.auth.service;

import com.twentythree.peech.common.utils.JWTUtils;
import com.twentythree.peech.common.utils.UserRoleConvertUtils;
import com.twentythree.peech.security.exception.JWTAuthenticationException;
import com.twentythree.peech.security.exception.LoginExceptionCode;
import com.twentythree.peech.security.jwt.JWTAuthenticationToken;
import com.twentythree.peech.user.dto.AccessAndRefreshToken;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.NoSuchElementException;

@Service
@RequiredArgsConstructor
public class ReissueAccessAndRefreshTokenService {

private final JWTUtils jwtUtils;

public AccessAndRefreshToken createNewToken(String refreshToken) {

try {
JWTAuthenticationToken authentication = (JWTAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();

Long userId = authentication.getPrincipal().getUserId();
GrantedAuthority Authority = authentication.getAuthorities()
.stream().findFirst().orElseThrow(() -> new NoSuchElementException("유저의 권한이 부여되지 않았습니다"));

String newAccessToken = jwtUtils.createAccessToken(userId, UserRoleConvertUtils
.convertStringToUserRole(Authority.getAuthority()));
String newRefreshToken = jwtUtils.createRefreshToken(userId, UserRoleConvertUtils
.convertStringToUserRole(Authority.getAuthority()));

return new AccessAndRefreshToken(newAccessToken, newRefreshToken);
}catch (Exception e){
throw new JWTAuthenticationException(LoginExceptionCode.LOGIN_EXCEPTION_CODE);
}
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.twentythree.peech.auth.service;

import com.twentythree.peech.security.jwt.JWTAuthentication;
import org.springframework.security.core.Authentication;

public class SecurityContextHolder {

public static Long getUserId() {
Authentication authentication = org.springframework.security.core.context.SecurityContextHolder.getContext().getAuthentication();
JWTAuthentication jwtAuthentication = (JWTAuthentication) authentication.getPrincipal();

return jwtAuthentication.getUserId();
}
}
19 changes: 19 additions & 0 deletions src/main/java/com/twentythree/peech/common/JwtProperties.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.twentythree.peech.common;

import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Getter
@Component
public class JwtProperties {

@Value("${jwt.secret.key}")
private String secretString;

@Value("${jwt.access.key}")
private String accessString;

@Value("${jwt.refresh.key}")
private String refreshString;
}
11 changes: 11 additions & 0 deletions src/main/java/com/twentythree/peech/common/app/AppInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.twentythree.peech.common.app;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class AppInfo {
private String appMinVersion;
private boolean appAvailable;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.twentythree.peech.common.app;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AppInfoController {

@Value("${app.version}")
private String appMinVersion;

@Value("${app.available}")
private boolean appAvailable;

@GetMapping("api/v1.1/app")
public ResponseEntity<AppInfo> getAppInfo() {

return ResponseEntity.status(200).body(new AppInfo(appMinVersion, appAvailable));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.twentythree.peech.common.dto.response;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class WrappedResponseBody<T> {

private int statusCode;
private T responseBody;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.twentythree.peech.common.exception;

public class AccessTokenExpiredException extends RuntimeException {
public AccessTokenExpiredException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.twentythree.peech.common.dto.UserAlreadyExistErrorVO;
import com.twentythree.peech.common.dto.ErrorDTO;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
Expand All @@ -22,10 +21,30 @@ public ResponseEntity<UserAlreadyExistErrorVO> UserAlreadyExistExceptionHandler(
return new ResponseEntity<>(alreadyExistErrorVO, HttpStatus.UNAUTHORIZED);
}

@ExceptionHandler(Unauthorized.class)
public ResponseEntity<Unauthorized> unauthorizedExceptionHandler(Unauthorized e) {
log.error(e.getMessage(), e);
Unauthorized unauthorized = new Unauthorized(e.getMessage());
return new ResponseEntity<>(unauthorized, HttpStatus.UNAUTHORIZED);
}

@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorDTO> baseExceptionHandler(Exception e) {
log.error("에러 발생", e);
ErrorDTO errorDTO = new ErrorDTO(e.getMessage());
return new ResponseEntity<>(errorDTO, HttpStatus.INTERNAL_SERVER_ERROR);
}

@ExceptionHandler(AccessTokenExpiredException.class)
public ResponseEntity<String> handleExpiredJWTTokenException(AccessTokenExpiredException e) {
log.error("access 토큰 만료 에러 발생", e);
// 410번 에러 코드로 응답
return new ResponseEntity<>(e.getMessage(), HttpStatus.GONE);
}

@ExceptionHandler(RefreshTokenExpiredException.class)
public ResponseEntity<String> handleExpiredJWTTokenException(RefreshTokenExpiredException e) {
log.error("refresh 토큰 만료 에러 발생", e);
return new ResponseEntity<>(e.getMessage(), HttpStatus.UNAUTHORIZED);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.twentythree.peech.common.exception;

import io.jsonwebtoken.ExpiredJwtException;

public class RefreshTokenExpiredException extends RuntimeException{
public RefreshTokenExpiredException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.twentythree.peech.common.exception;

public class Unauthorized extends RuntimeException{
public Unauthorized(String message) { super(message); }
}
Loading

0 comments on commit bfd2c35

Please sign in to comment.