Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RAC-83 #12

Merged
merged 36 commits into from
Oct 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
4aa1531
Merge pull request #7 from WE-ARE-RACCOONS/RAC-82
ywj9811 Oct 26, 2023
9dfe66f
RAC-79 feat: User 엔티티에 socialId 및 맀퍼 μΆ”κ°€
ay-eonii Oct 26, 2023
0911725
RAC-79 feat: WebClient μ„€μ • μΆ”κ°€
ay-eonii Oct 26, 2023
1767193
RAC-79 feat: 카카였 μ—‘μ„ΈμŠ€ 토큰 μœ νš¨μ„± 검증 및 μ‚¬μš©μž 정보 κ°€μ Έμ˜€κΈ° API 호좜
ay-eonii Oct 26, 2023
6efd6ff
RAC-79 feat: μƒˆλ‘œμš΄ μœ μ € μ €μž₯ κΈ°λŠ₯ κ΅¬ν˜„
ay-eonii Oct 26, 2023
664a322
RAC-79 feat: 카카였 둜그인 μœ μŠ€μΌ€μ΄μŠ€ μΆ”κ°€
ay-eonii Oct 26, 2023
36f5ee1
RAC-79 feat: 둜그인 컨트둀러 μΆ”κ°€
ay-eonii Oct 26, 2023
a8e0088
RAC-79 fix: ν•„μš”μ—†λŠ” μ–΄λ…Έν…Œμ΄μ…˜ μ‚­μ œ
ay-eonii Oct 27, 2023
3605ffb
RAC-79 rename: dto νŒ¨ν‚€μ§€λ₯Ό application νŒ¨ν‚€μ§€ μ•„λž˜λ‘œ μœ„μΉ˜ λ³€κ²½
ay-eonii Oct 27, 2023
b288caa
RAC-79 fix: `@Builder.Default`으둜 USER κΆŒν•œ μ΄ˆκΈ°ν™”
ay-eonii Oct 27, 2023
cedd212
RAC-79 fix: `KakaoSignInUseCase`에 μ‹ κ·œ μ‚¬μš©μž 식별 둜직 μΆ”κ°€
ay-eonii Oct 27, 2023
bc645e4
RAC-79 feat: AuthMapper μΆ”κ°€
ay-eonii Oct 27, 2023
96662d2
RAC-79 feat : 카카였 둜그인 연동
ywj9811 Oct 27, 2023
f64fa32
RAC-85 fix: 잘λͺ»λœ νƒ€μž… λ³€κ²½
ay-eonii Oct 27, 2023
22f94a8
RAC-85 feat: `userGetService`에 `socialId`둜 μœ μ € μ°ΎλŠ” 둜직 μΆ”κ°€
ay-eonii Oct 27, 2023
aa8b34c
RAC-85 feat: `AuthUserResponse` μΆ”κ°€
ay-eonii Oct 27, 2023
c747bfa
RAC-85 feat: UserDetails,UserDetailsService μ»€μŠ€ν…€
ay-eonii Oct 27, 2023
641412a
RAC-85 feat: JWT μ„€μ • 및 생성 둜직 κ΅¬ν˜„
ay-eonii Oct 27, 2023
4ad12f5
RAC-85 feat: JWT κ΄€λ ¨ application단 μΆ”κ°€
ay-eonii Oct 27, 2023
9f929a8
RAC-85 feat: JWT κ΄€λ ¨ presentation단 μΆ”κ°€
ay-eonii Oct 27, 2023
dbc6864
RAC-85 fix: `@Builder.Default` μ‚¬μš©ν•˜μ—¬ κ°’ μ΄ˆκΈ°ν™”
ay-eonii Oct 27, 2023
d296c05
docs : DockerFile
ywj9811 Oct 28, 2023
10b9bf4
RAC-66 docs : CD
ywj9811 Oct 28, 2023
80c2167
RAC-66 fix : CD
ywj9811 Oct 28, 2023
366bec3
RAC-85 fix: `Role.USER` λŒ€μ‹  `user.getRole()`으둜 JWT λ°œκΈ‰
ay-eonii Oct 28, 2023
bc94f0f
RAC-85 fix: API별 κΆŒν•œ λ³€κ²½
ay-eonii Oct 28, 2023
e9b8710
RAC-85 fix: cookie μ‚¬μš©ν•˜μ§€ μ•Šλ„λ‘ λ³€κ²½
ay-eonii Oct 28, 2023
b466f6d
Rename DockerFile to Dockerfile
ywj9811 Oct 28, 2023
8ae91c3
RAC-85 fix: `JwtFilter` ν•„μš”μ—†λŠ” 둜직 μ‚­μ œ
ay-eonii Oct 28, 2023
40fcffa
Merge pull request #9 from WE-ARE-RACCOONS/RAC-85
ay-eonii Oct 28, 2023
434f226
RAC-66 fix : resources 경둜 생성
ywj9811 Oct 28, 2023
780594c
Merge pull request #10 from WE-ARE-RACCOONS/main
ywj9811 Oct 28, 2023
44ec633
fix : imageλͺ… λ³€κ²½
ywj9811 Oct 28, 2023
bba58fc
RAC-66
ywj9811 Oct 28, 2023
cbda11f
RAC-66 fix : secretλ³€μˆ˜ 이름 μˆ˜μ •
ywj9811 Oct 28, 2023
463946c
RAC 78 feat: νšŒμ›κ°€μž… 및 둜그인
ay-eonii Oct 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions .github/workflows/CD-develop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Java CD with Gradle

on:
push:
branches: [ "develop" ]

permissions:
contents: read

jobs:
build:

runs-on: ubuntu-latest
env :
working-directory: ./
APPLICATION: ${{ secrets.APPLICATION }}

steps:
- uses: actions/checkout@v2
- name: Set up JDK 17
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'adopt'

- name: Cache Gradle packages
uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-

- name: Create application.yml
run: |
mkdir ./src/main/resources
echo "${{env.APPLICATION}}" > ./src/main/resources/application.yml

- name: Grant execute permission for gradlew
run: chmod +x gradlew
working-directory: ${{ env.working-directory }}

- name: Build with Gradle
run: ./gradlew build
working-directory: ${{ env.working-directory }}

- name: Cleanup Gradle Cache
if: ${{ always() }}
run: |
rm -f ~/.gradle/caches/modules-2/modules-2.lock
rm -f ~/.gradle/caches/modules-2/gc.properties

- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Build and Push Docker image
run: |
docker build -t ywj9811/postgraduate_develop:latest .
docker push ywj9811/postgraduate_develop:latest

- name: Deploy
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.EC2_SERVER_HOST }}
username: ${{ secrets.EC2_SERVER_USERNAME }}
key: ${{ secrets.PRIVATE_KEY }}
envs: GITHUB_SHA
script: |
docker-compose -f /home/ec2-user/config/docker-compose.yml down
docker-compose -f /home/ec2-user/config/docker-compose.yml pull
docker-compose -f /home/ec2-user/config/docker-compose.yml up -d --force-recreate --build


4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM openjdk:17-jdk
ARG JAR_FILE=./build/libs/postgraduate-0.0.1-SNAPSHOT.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.postgraduate.domain.auth.application.dto;

import com.postgraduate.domain.user.domain.entity.User;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class AuthUserResponse {
private User user;
private boolean isNew;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.postgraduate.domain.auth.application.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class JwtTokenResponse {
private String accessToken;
private String refreshToken;
private boolean isNew;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.postgraduate.domain.auth.application.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Builder
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class KakaoAccessTokenResponse {
Integer app_id;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.postgraduate.domain.auth.application.dto;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@AllArgsConstructor
@NoArgsConstructor
public class KakaoLoginRequest {
private String accessToken;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.postgraduate.domain.auth.application.dto;

import lombok.*;

@Builder
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class KakaoUserInfoResponse {
private Long id;
private KakaoAccount kakaoAccount;

@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class KakaoAccount {
private String email;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.postgraduate.domain.auth.application.mapper;

import com.postgraduate.domain.auth.application.dto.AuthUserResponse;
import com.postgraduate.domain.user.domain.entity.User;

public class AuthMapper {
public static AuthUserResponse mapToAuthUser(User user, boolean isNew) {
return AuthUserResponse.builder()
.user(user)
.isNew(isNew).build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.postgraduate.domain.auth.application.usecase.jwt;

import com.postgraduate.domain.auth.application.dto.JwtTokenResponse;
import com.postgraduate.domain.user.domain.entity.User;
import com.postgraduate.domain.user.domain.entity.constant.Role;
import com.postgraduate.global.jwt.JwtProvider;
import io.jsonwebtoken.Claims;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@RequiredArgsConstructor
@Service
public class JwtUseCase {
private final JwtProvider jwtProvider;

public JwtTokenResponse signIn(User user, boolean isNew) {
String accessToken = jwtProvider.generateToken(user.getUserId(), user.getRole(), false);
String refreshToken = jwtProvider.generateToken(user.getUserId(), user.getRole(), true);
return new JwtTokenResponse(accessToken, refreshToken, isNew);
}

public JwtTokenResponse regenerateToken(String refreshToken) {
jwtProvider.validateToken(refreshToken);
Claims claims = jwtProvider.parseClaims(refreshToken);
String role = claims.get("role", String.class);
String id = claims.getSubject();
String newAccessToken = jwtProvider.generateToken(Long.valueOf(id), Role.valueOf(role), false);
return new JwtTokenResponse(newAccessToken, null, false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.postgraduate.domain.auth.application.usecase.kakao;

import com.postgraduate.domain.auth.application.dto.KakaoAccessTokenResponse;
import com.postgraduate.domain.auth.application.dto.KakaoUserInfoResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;

@RequiredArgsConstructor
@Service
public class KakaoAccessTokenUseCase {

@Value("${app-id.kakao}")
private String APP_ID;
private final WebClient webClient;
private static final String USER_INFO_URI = "https://kapi.kakao.com/v2/user/me";
private static final String VALIDATE_TOKEN_URI = "https://kapi.kakao.com/v1/user/access_token_info";


public KakaoUserInfoResponse getUserInfo(String accessToken) {

verifyAccessToken(accessToken);

return webClient.get()
.uri(USER_INFO_URI)
.headers(h -> h.setBearerAuth(accessToken))
.retrieve()
.bodyToMono(KakaoUserInfoResponse.class)
.block();
}

private void verifyAccessToken(String accessToken) {
KakaoAccessTokenResponse kakaoAccessTokenResponse = webClient.get()
.uri(VALIDATE_TOKEN_URI)
.headers(h -> h.setBearerAuth(accessToken))
.retrieve()
.bodyToMono(KakaoAccessTokenResponse.class)
.block();

if (kakaoAccessTokenResponse == null ||
!kakaoAccessTokenResponse.getApp_id().toString().equals(APP_ID)) {
//TODO: μ˜ˆμ™Έ 처리
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.postgraduate.domain.auth.application.usecase.kakao;

import com.postgraduate.domain.auth.application.dto.AuthUserResponse;
import com.postgraduate.domain.auth.application.dto.KakaoUserInfoResponse;
import com.postgraduate.domain.auth.application.mapper.AuthMapper;
import com.postgraduate.domain.user.domain.entity.User;
import com.postgraduate.domain.user.domain.service.UserGetService;
import com.postgraduate.domain.user.domain.service.UserSaveService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

@Service
@RequiredArgsConstructor
public class KakaoSignInUseCase {
private final KakaoAccessTokenUseCase kakaoTokenUseCase;
private final UserSaveService userSaveService;
private final UserGetService userGetService;

@Transactional
public AuthUserResponse getUser(String token) {
KakaoUserInfoResponse userInfo = kakaoTokenUseCase.getUserInfo(token);
Long socialId = userInfo.getId();
Optional<User> user = userGetService.bySocialId(socialId);
if (user.isPresent()) {
return AuthMapper.mapToAuthUser(user.get(), false);
}

User newUser = userSaveService.saveUser(socialId);
return AuthMapper.mapToAuthUser(newUser, true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.postgraduate.domain.auth.presentation;

import com.postgraduate.domain.auth.application.dto.AuthUserResponse;
import com.postgraduate.domain.auth.application.usecase.jwt.JwtUseCase;
import com.postgraduate.domain.auth.application.usecase.kakao.KakaoSignInUseCase;
import com.postgraduate.domain.auth.application.dto.JwtTokenResponse;
import com.postgraduate.domain.auth.application.dto.KakaoLoginRequest;
import com.postgraduate.global.auth.AuthDetails;
import com.postgraduate.global.dto.ResponseDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import static com.postgraduate.domain.auth.presentation.contant.AuthResponseMessage.*;
import static org.springframework.http.HttpStatus.*;

@RestController
@RequiredArgsConstructor
@RequestMapping("/user")
@Tag(name = "AUTH Controller")
public class AuthController {
private final KakaoSignInUseCase kakaoSignInUseCase;
private final JwtUseCase jwtUseCase;

@PostMapping("/login")
@Operation(description = "카카였 둜그인")
public ResponseDto<JwtTokenResponse> getUserDetails(@RequestBody KakaoLoginRequest request) {
AuthUserResponse authUser = kakaoSignInUseCase.getUser(request.getAccessToken());
JwtTokenResponse jwtToken = jwtUseCase.signIn(authUser.getUser(), authUser.isNew());
return ResponseDto.create(OK.value(), SUCCESS_AUTH_MESSAGE.getMessage(), jwtToken);
}

@PostMapping("/refresh")
@Operation(description = "refreshToken 으둜 accessToken μž¬λ°œκΈ‰")
public ResponseDto<JwtTokenResponse> refresh(@AuthenticationPrincipal AuthDetails authDetails) {
Long userId = authDetails.getUserId();
String refreshToken = "";/*Redisμ—μ„œ userId둜 refreshToken 확인*/
JwtTokenResponse jwtToken = jwtUseCase.regenerateToken(refreshToken);
return ResponseDto.create(OK.value(), SUCCESS_REGENERATE_TOKEN_MESSAGE.getMessage(), jwtToken);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.postgraduate.domain.auth.presentation.contant;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum AuthResponseMessage {
SUCCESS_AUTH_MESSAGE("μ‚¬μš©μž 인증에 μ„±κ³΅ν•˜μ˜€μŠ΅λ‹ˆλ‹€."),
SUCCESS_REGENERATE_TOKEN_MESSAGE("토큰 μž¬λ°œκΈ‰μ— μ„±κ³΅ν•˜μ˜€μŠ΅λ‹ˆλ‹€.");
private final String message;
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ public class Payment {
private LocalDate deletedAt;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
@ColumnDefault("'IMPOSSIBLE'")
private Status status;
@Builder.Default
private Status status = Status.IMPOSSIBLE;
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ public class Review {
@Column(nullable = false)
private String content;
@Column(nullable = false)
@ColumnDefault("'REJECT'")
@Enumerated(EnumType.STRING)
private Status status;
@Builder.Default
private Status status = Status.REJECT;
@CreationTimestamp
private LocalDate createdAt;
@UpdateTimestamp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,10 @@ public static UserInfoResponse mapToInfo(User user) {
.point(user.getPoint())
.build();
}

public static User mapToUser(Long socialId) {
return User.builder()
.socialId(socialId)
.build();
}
}
Loading
Loading