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

8주차 산출물(Weekly -> Develop) #110

Merged
merged 7 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Set up SSH
uses: webfactory/ssh-agent@v0.5.3
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

Expand Down
36 changes: 36 additions & 0 deletions .github/workflows/testcode.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Run Tests on Pull Request

on:
pull_request:
branches:
- Weekly

jobs:
test:
runs-on: ubuntu-latest

services:
redis:
image: redis:alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'

- name: Run Tests
env:
JWT_SECRET: ${{ secrets.JWT_SECRET }}
run: ./gradlew test

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import com.example.sinitto.auth.dto.KakaoTokenResponse;
import com.example.sinitto.auth.dto.KakaoUserResponse;
import com.example.sinitto.auth.exception.KakaoEmailNotFoundException;
import com.example.sinitto.common.exception.NotFoundException;
import com.example.sinitto.common.properties.KakaoProperties;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
Expand Down Expand Up @@ -81,7 +81,7 @@ public KakaoUserResponse getUserInfo(String accessToken) {
url, HttpMethod.POST, request, KakaoUserResponse.class);

if (response.getBody().kakaoAccount().email() == null) {
throw new KakaoEmailNotFoundException("카카오 계정으로부터 전달받은 이메일이 없습니다.");
throw new NotFoundException("카카오 계정으로부터 전달받은 이메일이 없습니다.");
}

return response.getBody();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import com.example.sinitto.auth.dto.KakaoTokenResponse;
import com.example.sinitto.auth.entity.KakaoToken;
import com.example.sinitto.auth.exception.KakaoRefreshTokenExpirationException;
import com.example.sinitto.auth.exception.TokenNotFoundException;
import com.example.sinitto.auth.repository.KakaoTokenRepository;
import com.example.sinitto.common.exception.NotFoundException;
import com.example.sinitto.common.exception.UnauthorizedException;
import jakarta.transaction.Transactional;
import org.springframework.stereotype.Service;

Expand Down Expand Up @@ -36,11 +36,11 @@ public void saveKakaoToken(String email, KakaoTokenResponse kakaoTokenResponse)
@Transactional
public String getValidAccessTokenInServer(String email) {
KakaoToken kakaoToken = kakaoTokenRepository.findByMemberEmail(email)
.orElseThrow(() -> new TokenNotFoundException("email에 해당하는 카카오 토큰이 없습니다."));
.orElseThrow(() -> new NotFoundException("email에 해당하는 카카오 토큰이 없습니다."));

if (kakaoToken.isAccessTokenExpired()) {
if (kakaoToken.isRefreshTokenExpired()) {
throw new KakaoRefreshTokenExpirationException("카카오 리프레쉬 토큰이 만료되었습니다. 카카오 재 로그인 필요");
throw new UnauthorizedException("카카오 리프레쉬 토큰이 만료되었습니다. 카카오 재 로그인 필요");
}
KakaoTokenResponse kakaoTokenResponse = kakaoApiService.refreshAccessToken(kakaoToken.getRefreshToken());
kakaoToken.updateKakaoToken(kakaoTokenResponse.accessToken(), kakaoTokenResponse.refreshToken(), kakaoTokenResponse.expiresIn(), kakaoTokenResponse.refreshTokenExpiresIn());
Expand Down
32 changes: 22 additions & 10 deletions src/main/java/com/example/sinitto/auth/service/TokenService.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.example.sinitto.auth.service;

import com.example.sinitto.auth.dto.TokenResponse;
import com.example.sinitto.auth.exception.JWTExpirationException;
import com.example.sinitto.auth.exception.UnauthorizedException;
import com.example.sinitto.common.exception.AccessTokenExpiredException;
import com.example.sinitto.common.exception.InvalidJwtException;
import com.example.sinitto.common.exception.RefreshTokenStolenException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
Expand Down Expand Up @@ -53,14 +55,19 @@ public String generateRefreshToken(String email) {


public String extractEmail(String token) {
var claims = Jwts.parserBuilder()
.setSigningKey(secretKey)
.build()
.parseClaimsJws(token)
.getBody();
Claims claims;
try {
claims = Jwts.parserBuilder()
.setSigningKey(secretKey)
.build()
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
throw new InvalidJwtException(e.getMessage());
}

if (claims.getExpiration().before(new Date())) {
throw new JWTExpirationException("토큰이 만료되었습니다. 재로그인이 필요합니다.");
throw new AccessTokenExpiredException("액세스 토큰이 만료되었습니다. 리프레시 토큰으로 다시 액세스 토큰을 발급받으세요.");
}

return claims.getSubject();
Expand All @@ -70,8 +77,13 @@ public TokenResponse refreshAccessToken(String refreshToken) {
String email = extractEmail(refreshToken);

String storedRefreshToken = redisTemplate.opsForValue().get(email);
if (storedRefreshToken == null || !storedRefreshToken.equals(refreshToken)) {
throw new UnauthorizedException("만료되거나 이미 한번 사용된 리프레쉬 토큰입니다. 재로그인이 필요합니다.");

if (storedRefreshToken == null) {
throw new InvalidJwtException("토큰이 만료되었습니다. 재로그인이 필요합니다.");
}

if (!storedRefreshToken.equals(refreshToken)) {
throw new RefreshTokenStolenException("이미 한번 사용된 리프레시 토큰입니다. 리프레시 토큰이 탈취되었을 가능성이 있습니다.");
}

redisTemplate.delete(email);
Expand Down

This file was deleted.

13 changes: 5 additions & 8 deletions src/main/java/com/example/sinitto/callback/entity/Callback.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package com.example.sinitto.callback.entity;

import com.example.sinitto.callback.exception.AlreadyCompleteException;
import com.example.sinitto.callback.exception.AlreadyInProgressException;
import com.example.sinitto.callback.exception.AlreadyPendingCompleteException;
import com.example.sinitto.callback.exception.AlreadyWaitingException;
import com.example.sinitto.common.exception.ConflictException;
import com.example.sinitto.member.entity.Senior;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
Expand Down Expand Up @@ -100,16 +97,16 @@ public void changeStatusToComplete() {
private void throwStatusException(String message) {

if (this.status == Status.PENDING_COMPLETE) {
throw new AlreadyPendingCompleteException("완료 대기 상태의 콜백 입니다. " + message);
throw new ConflictException("완료 대기 상태의 콜백 입니다. " + message);
}
if (this.status == Status.COMPLETE) {
throw new AlreadyCompleteException("완료 상태의 콜백 입니다. " + message);
throw new ConflictException("완료 상태의 콜백 입니다. " + message);
}
if (this.status == Status.WAITING) {
throw new AlreadyWaitingException("대기 상태의 콜백 입니다. " + message);
throw new ConflictException("대기 상태의 콜백 입니다. " + message);
}
if (this.status == Status.IN_PROGRESS) {
throw new AlreadyInProgressException("진행 상태의 콜백 입니다. " + message);
throw new ConflictException("진행 상태의 콜백 입니다. " + message);
}
}

Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Loading