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

[Feature] 리프레시 토큰 적용 #61

Merged
merged 156 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from 152 commits
Commits
Show all changes
156 commits
Select commit Hold shift + click to select a range
1546f99
build : H2 database 추가
20jcode Sep 22, 2024
144d327
save
20jcode Sep 22, 2024
90c046e
build : JWT test secret key 추가
20jcode Sep 23, 2024
53dd77d
feat : 인증을 위한 user entity 추가
20jcode Sep 23, 2024
346e2f4
feat : jwt 기능 추가
20jcode Sep 23, 2024
359bdfc
feat : security config 추가
20jcode Sep 23, 2024
ae8474a
feat : 인증 관련 서비스 추가
20jcode Sep 23, 2024
ae5f932
feat : 로그인 필터 추가
20jcode Sep 23, 2024
4f7d7bb
delete : 불필요 테스트 클래스 삭제
20jcode Sep 23, 2024
1589120
fix : 불필요 import 제거, JwtFilter 오류 수정
20jcode Sep 23, 2024
df9fb6f
feat: 상태값 필드명 수정
yooookm Sep 23, 2024
40b5e66
feat: Merge Week3
yooookm Sep 23, 2024
bf8c87d
feat: chat 엔티티에 상태 관련 필드 추가
yooookm Sep 23, 2024
22eb891
feat: chart- 인지관리 엔티티 추가
yooookm Sep 23, 2024
7526e10
feat: 신체 활동 엔티티에서 외출 여부 객체 분리
yooookm Sep 23, 2024
828ce81
feat: 신체 활동 세부 조회 dto 작성
yooookm Sep 23, 2024
84d1960
feat: 신체 활동 세부 조회 dto 생성자 추가
yooookm Sep 23, 2024
254fd3c
feat: 간호 관리 세부 조회 dto 생성자 추가
yooookm Sep 23, 2024
ef1dab4
refactor: chart 관련 response는 별도 패키지로 분리
yooookm Sep 23, 2024
2ed7971
feat: 인지 관리 세부 조회 dto 작성
yooookm Sep 23, 2024
8c5430b
feat-chart 고나련 엔티티에 comment 추가
yooookm Sep 23, 2024
57140b8
chore: 불필요한 import문 삭제
yooookm Sep 23, 2024
e3a7f98
feat: 회복 훈련 response dto 작성
yooookm Sep 23, 2024
81ccc15
feat: chart detail response dto 작성
yooookm Sep 23, 2024
c4ae87d
refactor: 도메인 별 패키지 구조로 변경
yooookm Sep 23, 2024
2e1b0f4
feat: chartController 작성
yooookm Sep 23, 2024
30e8538
feat: 환자 id로 일지 전체 조회 함수에 pagable 추가
yooookm Sep 23, 2024
1c981b7
feat: chartRepository 작성
yooookm Sep 23, 2024
f671943
feat: util 클래스 생성
yooookm Sep 23, 2024
1b00ce0
feat: chart 관련 response 전체에 builder 어노테이션 추가
yooookm Sep 23, 2024
b2f77f0
feat: chart 관련 엔티티 전부에 getter 추가
yooookm Sep 23, 2024
bcaa1b7
chore: 필드명 카멜 케이스로 통일
yooookm Sep 23, 2024
4455fa2
feat: ChartDetailResponse 객체 생성 함수 구현
yooookm Sep 23, 2024
995c00c
feat: chartService 작성
yooookm Sep 23, 2024
589430c
feat: 차트id로 차트 세부 조회 api 구현
yooookm Sep 23, 2024
dfc7426
fix: 차트 특이사항 자료형 변경
yooookm Sep 24, 2024
6ce4ea9
Merge remote-tracking branch 'origin/Week3' into Week3-20j
20jcode Sep 24, 2024
8469c4d
계층 분리, 테이블명을 제외하고 전부 단수형 처리, 간단한 리팩토링 작업 (#24)
pykido Sep 25, 2024
a35e16d
Merge remote-tracking branch 'mainRepository/Week4' into Week4
20jcode Sep 25, 2024
ea6abc8
feat(security): 권한 Role 추가
20jcode Sep 25, 2024
baa9a27
feat : 보호자 회원가입 시 비밀번호 입력+암호화 추가
20jcode Sep 25, 2024
ba16a33
feat : SecurityConfig 임시 세팅 추가
20jcode Sep 25, 2024
a69324d
test : 보호자 회원가입 + 비밀번호 암호화 테스트
20jcode Sep 25, 2024
c061cf6
feat : 보호자 로그인 추가 + 권한 설정
20jcode Sep 25, 2024
50aaadd
refactor: 보호자, 요양사 api controller 분리
yooookm Sep 25, 2024
e67d005
feat: 차트 삭제 api 구현
yooookm Sep 25, 2024
39d530e
refactor: reseponse 전체 record 타입으로 변경
yooookm Sep 25, 2024
88362c3
feat: chart request 작성
yooookm Sep 25, 2024
735c1fd
feat: 엔티티 mapper 구현
yooookm Sep 25, 2024
ae92004
feat: ChartMapper에 id ignore 옵션 추가
yooookm Sep 25, 2024
f5d0675
Revert "feat: ChartMapper에 id ignore 옵션 추가"
yooookm Sep 25, 2024
ae45f3f
refactor : 불필요 클래스 삭제
20jcode Sep 26, 2024
329f437
feat : config jwt 적용된 상태로 수정
20jcode Sep 26, 2024
4170481
feat : JWT + security userdetails 설정
20jcode Sep 26, 2024
42bc41e
feat : 보호자 로그인 기능 추가
20jcode Sep 26, 2024
1634b97
test : 보호자 회원가입 및 로그인 테스트 - swagger
20jcode Sep 26, 2024
b55affc
feat : 기존 보호자 도메인 일부 수정 (권한 검사, ID 조회)
20jcode Sep 26, 2024
10f8910
refactor : 불필요 필드 삭제
20jcode Sep 26, 2024
b828b0f
bug : security 권한 설정 문제 발생
20jcode Sep 26, 2024
d89708f
feat: MapStruct 사용을 위한 getter,setter 추가
yooookm Sep 26, 2024
e1295c5
feat: chart 필드 세부 매핑 명시
yooookm Sep 26, 2024
a9ec1e9
test: MapStruct 매핑 확인 테스트 코드 작성
yooookm Sep 26, 2024
1fec4c6
feat: 사용자에 따른 api prefix 구분
yooookm Sep 26, 2024
77fb111
Merge remote-tracking branch 'refs/remotes/upstream/Week4' into feat-…
yooookm Sep 26, 2024
311d50a
merge: week4와 merge
yooookm Sep 26, 2024
1a9334f
feat: 차트 작성 api 구현
yooookm Sep 26, 2024
d894911
feat: 차트 수정 api 구현
yooookm Sep 26, 2024
f50205c
fix : Role 문제 해결
20jcode Sep 27, 2024
9940bcf
Merge remote-tracking branch 'refs/remotes/mainRepository/Week4' into…
20jcode Sep 27, 2024
2848492
feat : 컨트롤러 권한 검사 추가
20jcode Sep 27, 2024
f32d7a4
feat : 비밀번호 로직 추가
20jcode Sep 27, 2024
c45f08d
refactor : 불필요 로그 제거
20jcode Sep 27, 2024
d5bb387
feat : 역할에 따른 권한 부여 기능 추가
20jcode Sep 27, 2024
710d792
feat : 전화번호 조회 명시적 추가
20jcode Sep 27, 2024
6498521
fix : 불필요 import제거, 포멧팅
20jcode Sep 27, 2024
f7493f1
feat : careworker 로그인 권한 허용
20jcode Sep 27, 2024
79ac9b0
fix : 로그인 스프링 버전으로 변경
20jcode Sep 27, 2024
150cbb1
fix : careworker 컨트롤러 권한수정
20jcode Sep 27, 2024
c3b9ef5
fix : appversion 부분 와일드카드 적용
20jcode Sep 27, 2024
c341be8
fix : valid 추가
20jcode Sep 27, 2024
8578254
fix : bulid 패턴 제거
20jcode Sep 27, 2024
2e310a9
fix : careworker 휴대폰 번호 중복 검사
20jcode Sep 27, 2024
bf53dda
comment : 개행 조절
20jcode Sep 27, 2024
fd109a7
Merge remote-tracking branch 'refs/remotes/mainRepository/Week4' into…
20jcode Sep 29, 2024
485ac63
feat : 예외처리 로직 추가
20jcode Sep 30, 2024
96b5489
feat : 토큰 만료 error 추가
20jcode Sep 30, 2024
170f06d
feat : 토큰 만료 검사 추가
20jcode Sep 30, 2024
9355f1b
feat : 접근권한 관련 커스텀 필터 표현식 추가
20jcode Oct 1, 2024
d238a8d
save : 임시 careworker 저장
20jcode Oct 1, 2024
646b865
Merge remote-tracking branch 'refs/remotes/mainRepository/Week5' into…
20jcode Oct 1, 2024
0e52693
chore : LoginController 통일로 인한 삭제
20jcode Oct 1, 2024
2c3c5fa
chore : root 경로 변경
20jcode Oct 1, 2024
b8257b7
build : 설정값 분리
20jcode Oct 1, 2024
f0e20a2
chore : 요양원 Role 추가
20jcode Oct 1, 2024
8a70c30
feat : 로그인 기능 추가
20jcode Oct 1, 2024
310432e
chore : 불필요 test 삭제
20jcode Oct 1, 2024
579ef5b
fix : 잘못된 wildcard 사용 수정
20jcode Oct 1, 2024
6d689f0
feat : 로그인 endpoint 통일
20jcode Oct 2, 2024
87d5374
chore : 비밀번호 불일치 오류 추가 외
20jcode Oct 3, 2024
1a023c8
fix : 로그인 과정 로그인 불가 문제 해결
20jcode Oct 3, 2024
c54cbcf
chore : 불필요 클래스 삭제
20jcode Oct 7, 2024
edfacf1
feat : Principal 내부 InstitutionNumber 추가
20jcode Oct 7, 2024
e118078
feat : 권환확인 커스텀 어노테이션 추가
20jcode Oct 7, 2024
62c9f77
chore : 개행조절, 어노테이션 제거
20jcode Oct 7, 2024
bb4eed3
Merge remote-tracking branch 'refs/remotes/mainRepository/Week6' into…
20jcode Oct 7, 2024
94e9431
chore : merge 문제 해결
20jcode Oct 7, 2024
4e483a9
돌봄대상자/보호자/요양보호사 데이터 파일 입출력 기능 구현 (#49)
mogld Oct 10, 2024
cc61757
chore : 불필요 주석 삭제
20jcode Oct 10, 2024
2d29576
chore : getter 수정, 개행조절
20jcode Oct 10, 2024
e55e473
chore : 개행조절, 모호한 변수명 변경
20jcode Oct 10, 2024
c569a8b
chore : 시크릿키 수정, 이전버전 서비스 제거
20jcode Oct 11, 2024
929dc1f
Merge pull request #47 from 20jcode/Week4-security-merge-ready
20jcode Oct 11, 2024
bf00af6
merge: week6 브랜치와 merge
yooookm Oct 12, 2024
c22c3ae
fix: chart 관련 엔티티 cascade 설정
yooookm Oct 12, 2024
102b1ff
차트 작성 오류 수정 (#54)
yooookm Oct 15, 2024
6781e4c
fix: ChartDetailResponse 변경
yooookm Oct 17, 2024
dbc4470
chore : Repository 존재확인 메소드명 변경 (#56)
20jcode Oct 17, 2024
412f487
merge:Week7 브랜치와 merge
yooookm Oct 17, 2024
dc64ecf
fix: 불필요한 권한 어노테이션 제거
yooookm Oct 17, 2024
5a3ccc3
Merge pull request #57 from yooookm/feat-차트도메인crud
yooookm Oct 17, 2024
3d36629
chore : Repository 존재확인 메소드명 변경 롤백
20jcode Oct 17, 2024
404eba5
build: redis 관련 설정 추가
yooookm Oct 22, 2024
9b36071
Merge pull request #58 from 20jcode/Week7-repository-fix
yooookm Oct 22, 2024
95d4e2f
Merge branch 'Week7' of https://github.com/kakao-tech-campus-2nd-step…
yooookm Oct 22, 2024
991fe62
feat: redis config 설정
yooookm Oct 22, 2024
cdd9462
test: redis 연결 테스트 코드 작성
yooookm Oct 22, 2024
e7d55f3
refactor: Jwt 기본 정보 JwtUtil로 분리
yooookm Oct 22, 2024
e14c8df
feat: jwt 토큰 생성 시 issuer 추가
yooookm Oct 22, 2024
cabebe5
feat: redis에 refresh 토큰 저장, 조회, 삭제 기능 구현
yooookm Oct 22, 2024
0cd8d93
feat: 토큰 생성 시 사용할 TokenDTO 작성
yooookm Oct 22, 2024
1ed2946
feat: TokenDTO 필드 수정
yooookm Oct 22, 2024
cd63b5e
feat: refresh 토큰 생성 구현
yooookm Oct 22, 2024
80b6fc9
feat: access, refresh 토큰 생성 함수 적용
yooookm Oct 22, 2024
0490de9
feat: refresh 토큰 관련 exception code 선언
yooookm Oct 22, 2024
d582bd9
feat: 토큰 재발급 함수 구현
yooookm Oct 22, 2024
5deeca0
feat: refresh 토큰으로 재발급 api 구현
yooookm Oct 22, 2024
b3638a3
feat: blackList access token redis에 저장, 조회 기능 구현
yooookm Oct 22, 2024
f0a99c5
refactor: auth 관련 api 수정
yooookm Oct 22, 2024
f692feb
feat: 시큐리티 config 수정
yooookm Oct 22, 2024
84a20ea
feat: 로그아웃 기능 구현
yooookm Oct 22, 2024
2a9ac91
feat: 로그아웃 기능 수정
yooookm Oct 22, 2024
a1ef5dd
feat: 레디스에 토큰 저장 시 키 로직 변경
yooookm Oct 22, 2024
23a2be5
feat: 로그아웃 api 구현
yooookm Oct 22, 2024
971b048
feat: redis 블랙리스트 조회 로직 변경
yooookm Oct 22, 2024
81d408f
feat: 액세스 토큰으로 유저 조회시 검증 로직 추가
yooookm Oct 22, 2024
584a812
feat: 토큰 prefix 검증 로직 추가
yooookm Oct 22, 2024
c34bbc4
feat: security 인증 오류 처리 filter 구현
yooookm Oct 22, 2024
28233f3
feat: jwtFilter에서 인증 오류 시 오류 던지기
yooookm Oct 22, 2024
0fc65c3
feat: SecurityConfig에 인증 오류 handler filter 추가
yooookm Oct 22, 2024
9a7cec5
feat: token_prefix 검증 추가
yooookm Oct 22, 2024
67de30f
feat: 유효한 리프레시 토큰이 아닐 경우 리프레시 토큰 삭제
yooookm Oct 22, 2024
f7db827
fix: 블랙리스트 토큰 유효시간 수정
yooookm Oct 22, 2024
5f8aabd
chore: 암호화 알고리즘 상수 처리
yooookm Oct 30, 2024
12616e0
refactor: 필요없는 try-catch 제거
yooookm Oct 30, 2024
b2d37bf
merge-Week9 브랜치와 merge
yooookm Nov 1, 2024
d527bbd
docs: 로그인 관련 api swagger 명세 추가
yooookm Nov 1, 2024
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: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ dependencies {
// 데이터베이스
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'mysql:mysql-connector-java:8.0.33' // MySQL 의존성 추가 (MySQL JDBC 드라이버)
runtimeOnly 'com.h2database:h2'

// 보안
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
Expand Down Expand Up @@ -60,6 +61,9 @@ dependencies {
//POI
implementation 'org.apache.poi:poi-ooxml:5.3.0'
implementation 'org.apache.commons:commons-compress:1.27.1'

// Redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,24 @@
import dbdr.domain.careworker.dto.response.CareworkerResponseDTO;
import dbdr.domain.careworker.service.CareworkerService;
import jakarta.validation.Valid;
import java.net.URI;
import java.util.List;
import lombok.RequiredArgsConstructor;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.net.URI;
import java.util.List;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/${spring.app.version}/careworker")
@RequiredArgsConstructor
@PreAuthorize("hasAnyAuthority('ADMIN')")
public class CareworkerController {

private final CareworkerService careworkerService;
Expand All @@ -27,7 +31,7 @@ public class CareworkerController {

@GetMapping
public ResponseEntity<List<CareworkerResponseDTO>> getAllCareworkers(
@RequestParam(value = "institutionId", required = false) Long institutionId) {
@RequestParam(value = "institutionId", required = false) Long institutionId) {
List<CareworkerResponseDTO> careworkerList;
if (institutionId != null) {
careworkerList = careworkerService.getCareworkersByInstitution(institutionId);
Expand All @@ -39,25 +43,25 @@ public ResponseEntity<List<CareworkerResponseDTO>> getAllCareworkers(

@GetMapping("/{id}")
public ResponseEntity<CareworkerResponseDTO> getCareworkerById(
@PathVariable Long id) {
@PathVariable Long id) {
CareworkerResponseDTO careworker = careworkerService.getCareworkerById(id);
return ResponseEntity.ok(careworker);
}

@PostMapping
public ResponseEntity<CareworkerResponseDTO> createCareworker(
@Valid @RequestBody CareworkerRequestDTO careworkerDTO) {
@Valid @RequestBody CareworkerRequestDTO careworkerDTO) {
CareworkerResponseDTO newCareworker = careworkerService.createCareworker(careworkerDTO);
return ResponseEntity.created(
URI.create("/" + appVersion + "/careworker/" + newCareworker.getId()))
.body(newCareworker);
URI.create("/" + appVersion + "/careworker/" + newCareworker.getId()))
.body(newCareworker);
}

@PutMapping("/{id}")
public ResponseEntity<CareworkerResponseDTO> updateCareworker(@PathVariable Long id,
@Valid @RequestBody CareworkerRequestDTO careworkerDTO) {
@Valid @RequestBody CareworkerRequestDTO careworkerDTO) {
CareworkerResponseDTO updatedCareworker = careworkerService.updateCareworker(id,
careworkerDTO);
careworkerDTO);
return ResponseEntity.ok(updatedCareworker);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ public interface CareworkerRepository extends JpaRepository<Careworker, Long> {

List<Careworker> findByInstitutionId(Long institutionId);

boolean existsByEmail(String email);

Optional<Careworker> findByLineUserId(String userId);

List<Careworker> findByAlertTime(LocalTime currentTime);

Optional<Careworker> findByPhone(String phoneNumber);

boolean existsByEmail(String email);

boolean existsByPhone(String phone);
}

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

public record ChartDetailResponse(
Long chartId,
String conditionDisease,
BodyManagementResponse bodyManagement,
NursingManagementResponse nursingManagement,
CognitiveManagementResponse cognitiveManagement,
Expand Down
9 changes: 5 additions & 4 deletions src/main/java/dbdr/domain/chart/entity/Chart.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import dbdr.domain.core.base.entity.BaseEntity;
import dbdr.domain.recipient.entity.Recipient;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
Expand Down Expand Up @@ -33,19 +34,19 @@ public class Chart extends BaseEntity {
@Column(nullable = false, length = 500)
private String conditionDisease;

@OneToOne
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "body_management_id")
private BodyManagement bodyManagement;

@OneToOne
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "nursing_management_id")
private NursingManagement nursingManagement;

@OneToOne
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "recovery_training_id")
private RecoveryTraining recoveryTraining;

@OneToOne
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "cognitive_management_id")
private CognitiveManagement cognitiveManagement;

Expand Down
59 changes: 59 additions & 0 deletions src/main/java/dbdr/global/configuration/RedisConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package dbdr.global.configuration;


import io.lettuce.core.ClientOptions;
import io.lettuce.core.SocketOptions;
import java.time.Duration;
import org.springframework.beans.factory.annotation.Value;
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;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

@Value("${spring.data.redis.host}")
private String host;

@Value("${spring.data.redis.port}")
private int port;

@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration redisConfig = new RedisStandaloneConfiguration();
redisConfig.setHostName(host);
redisConfig.setPort(port);
return new LettuceConnectionFactory(redisConfig, clientConfig());
}

@Bean
public LettuceClientConfiguration clientConfig() {
return LettuceClientConfiguration.builder()
// 서버 배포시 ssl 사용으로 돌려야함
//.useSsl()
//.and()
.clientOptions(
ClientOptions.builder()
.socketOptions(SocketOptions.builder()
.connectTimeout(Duration.ofSeconds(10)) // 연결 타임아웃 설정
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

10초로 설정하신 이유가 있을까요? 그냥 궁금증입니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

보통 api 연결 테스트를 10초로 하더라구요
별 이유는 없습니다...ㅋㅋㅋㅋ

.build()
)
.build()
)
.build();
}

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());
return template;
}
}
1 change: 1 addition & 0 deletions src/main/java/dbdr/global/exception/ApplicationError.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public enum ApplicationError {
ACCESS_NOT_ALLOWED(HttpStatus.FORBIDDEN, "접근 권한이 없습니다."),
TOKEN_EXPIRED(HttpStatus.UNAUTHORIZED, "만료된 토큰입니다."),
PASSWORD_NOT_MATCH(HttpStatus.UNAUTHORIZED, "비밀번호가 일치하지 않습니다."),
REFRESH_TOKEN_EXPIRED(HttpStatus.UNAUTHORIZED, "유효하지 않은 리프레시 토큰입니다. 재로그인 해주세요."),

// Guardian (보호자)
GUARDIAN_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 보호자를 찾을 수가 없습니다."),
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/dbdr/global/util/api/JwtUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package dbdr.global.util.api;

public class JwtUtils {
pykido marked this conversation as resolved.
Show resolved Hide resolved
public static final String ISSUER = "CareBridge";
public static final String TOKEN_PREFIX = "Bearer ";
public static final long REFRESH_TOKEN_EXPIRATION_TIME = 60 * 60 * 24 * 30L; // 30일
public static final long ACCESS_TOKEN_EXPIRATION_TIME = 60 * 60; // 1시간

private JwtUtils() {
}
}
70 changes: 70 additions & 0 deletions src/main/java/dbdr/security/config/ExceptionHandlingFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package dbdr.security.config;


import com.fasterxml.jackson.databind.ObjectMapper;
import dbdr.global.util.api.ApiUtils;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.security.SignatureException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

@Component
@Slf4j
public class ExceptionHandlingFilter extends OncePerRequestFilter {

private final ObjectMapper objectMapper = new ObjectMapper();

@Override
protected void doFilterInternal(@NonNull HttpServletRequest request,
@NonNull HttpServletResponse response,
@NonNull FilterChain filterChain) throws ServletException, IOException {
try {
filterChain.doFilter(request, response);
} catch (Exception ex) {
handleException(request, response, ex);
}
}

private void handleException(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws IOException {
ApiUtils.ApiResult<?> apiResult;
HttpStatus status = HttpStatus.UNAUTHORIZED;

if (ex instanceof ExpiredJwtException) {
apiResult = ApiUtils.error(status, "토큰이 만료되었습니다.");
} else if (ex instanceof UnsupportedJwtException) {
apiResult = ApiUtils.error(status, "지원하지 않는 토큰 형식입니다.");
} else if (ex instanceof MalformedJwtException) {
apiResult = ApiUtils.error(status, "토큰의 형식이 올바르지 않습니다.");
} else if (ex instanceof SignatureException || ex instanceof SecurityException) {
apiResult = ApiUtils.error(status, "토큰의 서명이 유효하지 않습니다.");
} else if (ex instanceof IllegalArgumentException) {
apiResult = ApiUtils.error(status, "토큰이 제공되지 않았습니다.");
} else if (ex instanceof JwtException) {
apiResult = ApiUtils.error(status, "유효하지 않은 토큰입니다.");
} else {
status = HttpStatus.INTERNAL_SERVER_ERROR;
apiResult = ApiUtils.error(status, "서버 오류가 발생했습니다.");
}

log.error("Security Exception 발생: [{}] {}", request.getRequestURI(), ex.getMessage());

response.setStatus(status.value());
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");

String jsonResponse = objectMapper.writeValueAsString(apiResult);
response.getWriter().write(jsonResponse);
}
}
13 changes: 11 additions & 2 deletions src/main/java/dbdr/security/config/JwtFilter.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package dbdr.security.config;

import dbdr.security.service.JwtProvider;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.security.SignatureException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
Expand All @@ -20,17 +25,21 @@ public class JwtFilter extends OncePerRequestFilter {

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
FilterChain filterChain) throws ServletException, IOException {

String token = request.getHeader("Authorization");
String token = jwtProvider.extractToken(request);

if (token != null) {
try {
//jwtProvider.validateToken(token);
Authentication authentication = jwtProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
} catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException |
SignatureException | SecurityException | IllegalArgumentException ex) {
throw ex;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ex보단 에러명을 지정해서 던져주는 건 어떠신가요? 원래 저희가 사용하던 ApplicationError 대신 이걸 사용하신 이유가 있을까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

토큰 검증에서 발생하는 오류는 저희가 직접 던지는 오류가 아니에요!
그래서 jwt 관련 오류가 발생했을 때를 대비해서 짠 로직입니다.
근데 혜연님 말씀대로 굳이 에러 그대로 throw할 필요는 없는 것 같아요. 수정하겠습니다!

} catch (Exception e) {
log.debug("토큰 유저 정보 추출 실패 : {}", e.getMessage());
throw new JwtException("유효하지 않은 토큰입니다.");
}
}

Expand Down
Loading