Skip to content

Commit ff4cfad

Browse files
committed
Merge remote-tracking branch 'origin/dev' into dev
2 parents 40d8713 + 6362e2e commit ff4cfad

File tree

7 files changed

+61
-16
lines changed

7 files changed

+61
-16
lines changed

src/main/java/dmu/dasom/api/domain/google/service/GoogleApiService.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,37 +7,44 @@
77
import com.google.api.services.sheets.v4.Sheets;
88
import com.google.api.services.sheets.v4.model.UpdateValuesResponse;
99
import com.google.api.services.sheets.v4.model.ValueRange;
10+
import com.google.auth.Credentials;
1011
import com.google.auth.http.HttpCredentialsAdapter;
1112
import com.google.auth.oauth2.GoogleCredentials;
1213
import dmu.dasom.api.domain.common.exception.CustomException;
1314
import dmu.dasom.api.domain.common.exception.ErrorCode;
15+
import lombok.RequiredArgsConstructor;
1416
import org.slf4j.Logger;
1517
import org.slf4j.LoggerFactory;
1618
import org.springframework.beans.factory.annotation.Value;
1719
import org.springframework.core.io.ClassPathResource;
1820
import org.springframework.stereotype.Service;
1921

22+
import java.io.ByteArrayInputStream;
2023
import java.io.IOException;
24+
import java.nio.charset.StandardCharsets;
2125
import java.security.GeneralSecurityException;
2226
import java.util.Collections;
2327
import java.util.List;
2428

29+
@RequiredArgsConstructor
2530
@Service
2631
public class GoogleApiService {
2732

2833
private static final Logger logger = LoggerFactory.getLogger(GoogleApiService.class);
2934
private static final String APPLICATION_NAME = "Recruit Form";
3035
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
31-
@Value("${google.credentials.file.path}")
32-
private String credentialsFilePath;
36+
@Value("${google.credentials.json}")
37+
private String credentialsJson;
3338
private Sheets sheetsService;
3439

35-
// 해당 메소드는 sheets의 인스턴스를 얻는데 사용
40+
// Google Sheets API 서비스 객체를 생성하는 메소드
3641
private Sheets getSheetsService() throws IOException, GeneralSecurityException{
3742
if(sheetsService == null){
43+
ByteArrayInputStream credentialsStream = new ByteArrayInputStream(credentialsJson.getBytes(StandardCharsets.UTF_8));
3844
GoogleCredentials credentials = GoogleCredentials
39-
.fromStream(new ClassPathResource(credentialsFilePath).getInputStream())
45+
.fromStream(credentialsStream)
4046
.createScoped(Collections.singletonList("https://www.googleapis.com/auth/spreadsheets"));
47+
4148
sheetsService = new Sheets.Builder(GoogleNetHttpTransport.newTrustedTransport(), JSON_FACTORY, new HttpCredentialsAdapter(credentials))
4249
.setApplicationName(APPLICATION_NAME)
4350
.build();

src/main/java/dmu/dasom/api/domain/member/controller/MemberController.java

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import dmu.dasom.api.domain.common.exception.ErrorResponse;
44
import dmu.dasom.api.domain.member.dto.SignupRequestDto;
55
import dmu.dasom.api.domain.member.service.MemberService;
6+
import dmu.dasom.api.global.auth.dto.TokenBox;
7+
import dmu.dasom.api.global.auth.userdetails.UserDetailsImpl;
68
import io.swagger.v3.oas.annotations.Operation;
79
import io.swagger.v3.oas.annotations.media.Content;
810
import io.swagger.v3.oas.annotations.media.ExampleObject;
@@ -11,11 +13,10 @@
1113
import io.swagger.v3.oas.annotations.responses.ApiResponses;
1214
import jakarta.validation.Valid;
1315
import lombok.RequiredArgsConstructor;
16+
import org.springframework.http.HttpHeaders;
1417
import org.springframework.http.ResponseEntity;
15-
import org.springframework.web.bind.annotation.PostMapping;
16-
import org.springframework.web.bind.annotation.RequestBody;
17-
import org.springframework.web.bind.annotation.RequestMapping;
18-
import org.springframework.web.bind.annotation.RestController;
18+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
19+
import org.springframework.web.bind.annotation.*;
1920

2021
@RestController
2122
@RequestMapping("/api")
@@ -39,16 +40,32 @@ public class MemberController {
3940
),
4041
@ExampleObject(
4142
name = "이메일 또는 비밀번호 형식 올바르지 않음",
42-
value = "{ \"code\": \"C007\", \"message\": \"요청한 값이 올바르지 않습니다.\" }"
43-
)
44-
}
45-
)
46-
)
47-
})
43+
value = "{ \"code\": \"C007\", \"message\": \"요청한 값이 올바르지 않습니다.\" }")}))})
4844
@PostMapping("/auth/signup")
4945
public ResponseEntity<Void> signUp(@Valid @RequestBody final SignupRequestDto request) {
5046
memberService.signUp(request);
5147
return ResponseEntity.ok().build();
5248
}
5349

50+
@Operation(summary = "토큰 갱신")
51+
@ApiResponses(value = {
52+
@ApiResponse(responseCode = "200", description = "토큰 갱신 성공 (Header로 토큰 반환)"),
53+
@ApiResponse(responseCode = "400", description = "실패 케이스",
54+
content = @Content(
55+
mediaType = "application/json",
56+
schema = @Schema(implementation = ErrorResponse.class),
57+
examples = {
58+
@ExampleObject(
59+
name = "RefreshToken 만료",
60+
value = "{ \"code\": \"C004\", \"message\": \"토큰이 만료되었습니다.\" }")}))})
61+
@GetMapping("/auth/rotation")
62+
public ResponseEntity<Void> tokenRotation(@AuthenticationPrincipal final UserDetailsImpl userDetails) {
63+
final TokenBox tokenBox = memberService.tokenRotation(userDetails);
64+
final HttpHeaders headers = new HttpHeaders();
65+
headers.add("Access-Token", tokenBox.getAccessToken());
66+
headers.add("Refresh-Token", tokenBox.getRefreshToken());
67+
68+
return ResponseEntity.ok().headers(headers).build();
69+
}
70+
5471
}

src/main/java/dmu/dasom/api/domain/member/service/MemberService.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import dmu.dasom.api.domain.member.dto.SignupRequestDto;
44
import dmu.dasom.api.domain.member.entity.Member;
5+
import dmu.dasom.api.global.auth.dto.TokenBox;
6+
import dmu.dasom.api.global.auth.userdetails.UserDetailsImpl;
57

68
public interface MemberService {
79

@@ -11,4 +13,6 @@ public interface MemberService {
1113

1214
void signUp(final SignupRequestDto request);
1315

16+
TokenBox tokenRotation(final UserDetailsImpl userDetails);
17+
1418
}

src/main/java/dmu/dasom/api/domain/member/service/MemberServiceImpl.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
import dmu.dasom.api.domain.member.dto.SignupRequestDto;
66
import dmu.dasom.api.domain.member.entity.Member;
77
import dmu.dasom.api.domain.member.repository.MemberRepository;
8+
import dmu.dasom.api.global.auth.dto.TokenBox;
9+
import dmu.dasom.api.global.auth.jwt.JwtUtil;
10+
import dmu.dasom.api.global.auth.userdetails.UserDetailsImpl;
811
import lombok.RequiredArgsConstructor;
912
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
1013
import org.springframework.stereotype.Service;
@@ -17,6 +20,7 @@ public class MemberServiceImpl implements MemberService {
1720

1821
private final BCryptPasswordEncoder encoder;
1922
private final MemberRepository memberRepository;
23+
private final JwtUtil jwtUtil;
2024

2125
// 이메일로 사용자 조회
2226
@Override
@@ -42,4 +46,10 @@ public void signUp(final SignupRequestDto request) {
4246
memberRepository.save(request.toEntity(encoder.encode(request.getPassword())));
4347
}
4448

49+
// 토큰 갱신
50+
@Override
51+
public TokenBox tokenRotation(final UserDetailsImpl userDetails) {
52+
return jwtUtil.tokenRotation(userDetails);
53+
}
54+
4555
}

src/main/java/dmu/dasom/api/global/auth/config/SecurityConfig.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public SecurityFilterChain filterChain(final HttpSecurity http, final Authentica
6868
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
6969
.authorizeHttpRequests(auth -> auth
7070
.requestMatchers("/api/admin/**").hasRole(Role.ROLE_ADMIN.getName())
71-
.requestMatchers("/api/auth/logout").authenticated()
71+
.requestMatchers("/api/auth/logout", "/api/auth/rotation").authenticated()
7272
.anyRequest().permitAll())
7373
.addFilterBefore(jwtFilter, CustomAuthenticationFilter.class)
7474
.addFilterAt(customAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)

src/main/java/dmu/dasom/api/global/auth/jwt/JwtUtil.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import dmu.dasom.api.domain.common.exception.CustomException;
44
import dmu.dasom.api.domain.common.exception.ErrorCode;
55
import dmu.dasom.api.global.auth.dto.TokenBox;
6+
import dmu.dasom.api.global.auth.userdetails.UserDetailsImpl;
67
import io.jsonwebtoken.*;
78
import io.jsonwebtoken.security.SignatureException;
89
import org.springframework.beans.factory.annotation.Value;
@@ -130,4 +131,10 @@ public boolean isExpired(final String token) {
130131
}
131132
}
132133

134+
// Access, Refresh 토큰 갱신
135+
public TokenBox tokenRotation(final UserDetailsImpl userDetails) {
136+
blacklistTokens(userDetails.getUsername());
137+
return generateTokenBox(userDetails.getUsername());
138+
}
139+
133140
}

src/main/resources/application-credentials.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@ jwt:
2121
refresh-token-expiration: ${JWT_REFRESH_TOKEN_EXPIRATION}
2222
google:
2323
credentials:
24-
path: ${GOOGLE_CREDENTIALS_PATH}
24+
json: ${GOOGLE_CREDENTIALS_JSON}
2525
spreadsheet:
2626
id: ${GOOGLE_SPREADSHEET_ID}

0 commit comments

Comments
 (0)