-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* chore: rest docs 의존성 제거 * refactor: 패키지 구조 변경 * docs: .env 제외 * feat: 커스텀 유저 서비스 구현 * feat: 프로퍼티 세팅 및 JWT 설정 추가 * feat: 쿠키 유틸리티 구현 * feat: 소셜 로그인 성공 시 토큰 발급해주는 핸들러 구현 * feat: 시큐리티 관련 상수 클래스 추가 * refactor: 토큰 프로퍼티 객체 구조 개선 * feat: 토큰 생성 유틸리티 구현 * feat: 소셜 로그인 성공 핸들러에 토큰 발급 로직 추가 * docs: JWT 유틸리티에 주석 추가 * chore: 레디스 관련 세팅 * feat: 레디스 리프레시 토큰 구현 * refactor: 토큰 전송 시 DTO 사용하도록 리팩토링 * style: spotless 적용 * feat: JwtService 구현 및 적용 * refactor: TokenType을 JwtConstant로 리팩토링 * feat: JwtService 토큰 파싱 및 조회 로직 구현 * refactor: 쿠키 maxAge 제거 * feat: PrincipalDetails 구현 * feat: JWT 파싱 로직 추가 * feat: 엑세스 토큰 만료 체크 로직 추가 * feat: 로그 제거 및 파싱 로직 수정 * feat: 엑세스 토큰 재발급 로직 추가 * feat: JWT 필터 구현 * chore: 시큐리티 설정 추가 * chore: 레디스 컨테이너 설정 * test: 레디스 테스트 설정 추가 * chore: 테스트용 임시 값 추가 * refactor: setter로 변경 * fix: 생성자 사용하도록 수정 * chore: redis 컨테이너 설정 추가 * chore: 레디스 만료 이벤트 수신하지 않도록 변경 * style: spotless 적용 * chore: setup-java 버전 변경 * refactor: 사용하지 않는 메서드 및 의존성 제거
- Loading branch information
Showing
32 changed files
with
787 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,14 +13,18 @@ jobs: | |
uses: actions/[email protected] | ||
|
||
- name: JDK 설치 | ||
uses: actions/setup-java@v3 | ||
uses: actions/setup-java@v4 | ||
with: | ||
distribution: temurin | ||
java-version: 17 | ||
|
||
- name: gradlew 권한 부여 | ||
run: chmod +x ./gradlew | ||
|
||
# Redis 컨테이너 실행 | ||
- name: Start containers | ||
run: docker-compose -f ./docker-compose-test.yaml up -d | ||
|
||
- name: Gradle Build | ||
uses: gradle/gradle-build-action@v2 | ||
with: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,3 +38,6 @@ out/ | |
|
||
### ETC ### | ||
.DS_Store | ||
|
||
### Secrets ### | ||
.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
version: "3.8" | ||
|
||
services: | ||
redis: | ||
image: "redis:alpine" | ||
ports: | ||
- "6379:6379" | ||
environment: | ||
- TZ=Asia/Seoul |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 0 additions & 25 deletions
25
src/main/java/com/gdschongik/gdsc/common/config/WebSecurityConfig.java
This file was deleted.
Oops, something went wrong.
96 changes: 96 additions & 0 deletions
96
src/main/java/com/gdschongik/gdsc/domain/auth/application/JwtService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package com.gdschongik.gdsc.domain.auth.application; | ||
|
||
import static com.gdschongik.gdsc.global.common.constant.SecurityConstant.*; | ||
|
||
import com.gdschongik.gdsc.domain.auth.dao.RefreshTokenRepository; | ||
import com.gdschongik.gdsc.domain.auth.domain.RefreshToken; | ||
import com.gdschongik.gdsc.domain.auth.dto.AccessTokenDto; | ||
import com.gdschongik.gdsc.domain.auth.dto.RefreshTokenDto; | ||
import com.gdschongik.gdsc.domain.member.domain.MemberRole; | ||
import com.gdschongik.gdsc.global.util.JwtUtil; | ||
import io.jsonwebtoken.ExpiredJwtException; | ||
import java.util.Optional; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.stereotype.Service; | ||
|
||
@Slf4j | ||
@Service | ||
@RequiredArgsConstructor | ||
public class JwtService { | ||
|
||
private final JwtUtil jwtUtil; | ||
private final RefreshTokenRepository refreshTokenRepository; | ||
|
||
public AccessTokenDto createAccessToken(Long memberId, MemberRole memberRole) { | ||
return jwtUtil.generateAccessToken(memberId, memberRole); | ||
} | ||
|
||
public RefreshTokenDto createRefreshToken(Long memberId) { | ||
RefreshTokenDto refreshTokenDto = jwtUtil.generateRefreshToken(memberId); | ||
saveRefreshTokenToRedis(refreshTokenDto); | ||
return refreshTokenDto; | ||
} | ||
|
||
private void saveRefreshTokenToRedis(RefreshTokenDto refreshTokenDto) { | ||
RefreshToken refreshToken = RefreshToken.builder() | ||
.memberId(refreshTokenDto.memberId()) | ||
.token(refreshTokenDto.tokenValue()) | ||
.ttl(refreshTokenDto.ttl()) | ||
.build(); | ||
refreshTokenRepository.save(refreshToken); | ||
} | ||
|
||
public AccessTokenDto retrieveAccessToken(String accessTokenValue) { | ||
try { | ||
return jwtUtil.parseAccessToken(accessTokenValue); | ||
} catch (Exception e) { | ||
return null; | ||
} | ||
} | ||
|
||
public RefreshTokenDto retrieveRefreshToken(String refreshTokenValue) { | ||
RefreshTokenDto refreshTokenDto = parseRefreshToken(refreshTokenValue); | ||
|
||
if (refreshTokenDto == null) { | ||
return null; | ||
} | ||
|
||
// 파싱된 DTO와 일치하는 토큰이 Redis에 저장되어 있는지 확인 | ||
Optional<RefreshToken> refreshToken = getRefreshTokenFromRedis(refreshTokenDto.memberId()); | ||
|
||
// Redis에 토큰이 존재하고, 쿠키의 토큰과 값이 일치하면 DTO 반환 | ||
if (refreshToken.isPresent() | ||
&& refreshTokenDto.tokenValue().equals(refreshToken.get().getToken())) { | ||
return refreshTokenDto; | ||
} | ||
|
||
// Redis에 토큰이 존재하지 않거나, 쿠키의 토큰과 값이 일치하지 않으면 null 반환 | ||
return null; | ||
} | ||
|
||
private Optional<RefreshToken> getRefreshTokenFromRedis(Long memberId) { | ||
// TODO: CustomException으로 바꾸기 | ||
return refreshTokenRepository.findByMemberId(memberId); | ||
} | ||
|
||
private RefreshTokenDto parseRefreshToken(String refreshTokenValue) { | ||
try { | ||
return jwtUtil.parseRefreshToken(refreshTokenValue); | ||
} catch (Exception e) { | ||
return null; | ||
} | ||
} | ||
|
||
public AccessTokenDto reissueAccessTokenIfExpired(String accessTokenValue) { | ||
// AT가 만료된 경우 AT를 재발급, 만료되지 않은 경우 null 반환 | ||
try { | ||
jwtUtil.parseAccessToken(accessTokenValue); | ||
return null; | ||
} catch (ExpiredJwtException e) { | ||
Long memberId = Long.parseLong(e.getClaims().getSubject()); | ||
MemberRole memberRole = MemberRole.valueOf(e.getClaims().get(TOKEN_ROLE_NAME, String.class)); | ||
return createAccessToken(memberId, memberRole); | ||
} | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
src/main/java/com/gdschongik/gdsc/domain/auth/dao/RefreshTokenRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.gdschongik.gdsc.domain.auth.dao; | ||
|
||
import com.gdschongik.gdsc.domain.auth.domain.RefreshToken; | ||
import java.util.Optional; | ||
import org.springframework.data.repository.CrudRepository; | ||
|
||
public interface RefreshTokenRepository extends CrudRepository<RefreshToken, Long> { | ||
Optional<RefreshToken> findByMemberId(Long aLong); | ||
} |
27 changes: 27 additions & 0 deletions
27
src/main/java/com/gdschongik/gdsc/domain/auth/domain/RefreshToken.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package com.gdschongik.gdsc.domain.auth.domain; | ||
|
||
import lombok.Builder; | ||
import lombok.Getter; | ||
import org.springframework.data.annotation.Id; | ||
import org.springframework.data.redis.core.RedisHash; | ||
import org.springframework.data.redis.core.TimeToLive; | ||
|
||
@Getter | ||
@RedisHash(value = "refreshToken") | ||
public class RefreshToken { | ||
|
||
@Id | ||
private Long memberId; | ||
|
||
private String token; | ||
|
||
@TimeToLive | ||
private long ttl; | ||
|
||
@Builder | ||
public RefreshToken(Long memberId, String token, long ttl) { | ||
this.memberId = memberId; | ||
this.token = token; | ||
this.ttl = ttl; | ||
} | ||
} |
5 changes: 5 additions & 0 deletions
5
src/main/java/com/gdschongik/gdsc/domain/auth/dto/AccessTokenDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.gdschongik.gdsc.domain.auth.dto; | ||
|
||
import com.gdschongik.gdsc.domain.member.domain.MemberRole; | ||
|
||
public record AccessTokenDto(Long memberId, MemberRole memberRole, String tokenValue) {} |
3 changes: 3 additions & 0 deletions
3
src/main/java/com/gdschongik/gdsc/domain/auth/dto/RefreshTokenDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package com.gdschongik.gdsc.domain.auth.dto; | ||
|
||
public record RefreshTokenDto(Long memberId, String tokenValue, Long ttl) {} |
2 changes: 1 addition & 1 deletion
2
...gik/gdsc/common/model/BaseTimeEntity.java → ...c/domain/common/model/BaseTimeEntity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
src/main/java/com/gdschongik/gdsc/domain/member/dao/MemberRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.gdschongik.gdsc.domain.member.dao; | ||
|
||
import com.gdschongik.gdsc.domain.member.domain.Member; | ||
import java.util.Optional; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface MemberRepository extends JpaRepository<Member, Long> { | ||
|
||
Optional<Member> findByOauthId(String oauthId); | ||
} |
2 changes: 1 addition & 1 deletion
2
src/main/java/com/gdschongik/gdsc/domain/member/domain/Member.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
src/main/java/com/gdschongik/gdsc/global/common/constant/JwtConstant.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.gdschongik.gdsc.global.common.constant; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
|
||
@Getter | ||
@AllArgsConstructor | ||
public enum JwtConstant { | ||
ACCESS_TOKEN(Constants.ACCESS_TOKEN_COOKIE_NAME), | ||
REFRESH_TOKEN(Constants.REFRESH_TOKEN_COOKIE_NAME); | ||
|
||
private final String cookieName; | ||
|
||
private static class Constants { | ||
public static final String ACCESS_TOKEN_COOKIE_NAME = "accessToken"; | ||
public static final String REFRESH_TOKEN_COOKIE_NAME = "refreshToken"; | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
src/main/java/com/gdschongik/gdsc/global/common/constant/SecurityConstant.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.gdschongik.gdsc.global.common.constant; | ||
|
||
public class SecurityConstant { | ||
|
||
public static final String REGISTRATION_REQUIRED_HEADER = "Registration-Required"; | ||
public static final String TOKEN_ROLE_NAME = "role"; | ||
|
||
private SecurityConstant() {} | ||
} |
2 changes: 1 addition & 1 deletion
2
...chongik/gdsc/common/config/JpaConfig.java → ...chongik/gdsc/global/config/JpaConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
src/main/java/com/gdschongik/gdsc/global/config/PropertyConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.gdschongik.gdsc.global.config; | ||
|
||
import com.gdschongik.gdsc.global.property.JwtProperty; | ||
import com.gdschongik.gdsc.global.property.RedisProperty; | ||
import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
@EnableConfigurationProperties({JwtProperty.class, RedisProperty.class}) | ||
@Configuration | ||
public class PropertyConfig {} |
35 changes: 35 additions & 0 deletions
35
src/main/java/com/gdschongik/gdsc/global/config/RedisConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package com.gdschongik.gdsc.global.config; | ||
|
||
import com.gdschongik.gdsc.global.property.RedisProperty; | ||
import java.time.Duration; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.data.redis.connection.RedisConnectionFactory; | ||
import org.springframework.data.redis.connection.RedisStandaloneConfiguration; | ||
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration; | ||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; | ||
|
||
@RequiredArgsConstructor | ||
@Configuration | ||
public class RedisConfig { | ||
|
||
private final RedisProperty redisProperty; | ||
|
||
@Bean | ||
public RedisConnectionFactory redisConnectionFactory() { | ||
RedisStandaloneConfiguration redisConfig = | ||
new RedisStandaloneConfiguration(redisProperty.getHost(), redisProperty.getPort()); | ||
|
||
if (!redisProperty.getPassword().isBlank()) { | ||
redisConfig.setPassword(redisProperty.getPassword()); | ||
} | ||
|
||
LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder() | ||
.commandTimeout(Duration.ofSeconds(1)) | ||
.shutdownTimeout(Duration.ZERO) | ||
.build(); | ||
|
||
return new LettuceConnectionFactory(redisConfig, clientConfig); | ||
} | ||
} |
Oops, something went wrong.