-
Notifications
You must be signed in to change notification settings - Fork 0
[chore] 운영서버로 배포 25/08/13 #215
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
Changes from all commits
c4d0d4d
19b06e0
0af20a9
81e3c30
ed13e83
a5ead8a
2a19181
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,6 +2,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| import jakarta.servlet.FilterChain; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import jakarta.servlet.ServletException; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import jakarta.servlet.http.Cookie; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import jakarta.servlet.http.HttpServletRequest; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import jakarta.servlet.http.HttpServletResponse; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import konkuk.thip.common.exception.AuthException; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -68,10 +69,20 @@ protected void doFilterInternal(HttpServletRequest request, | |||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| private String extractToken(HttpServletRequest request) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| // 1. Authorization 헤더 우선 (앱) | ||||||||||||||||||||||||||||||||||||||||||||||||
| String authorization = request.getHeader(JWT_HEADER_KEY.getValue()); | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (authorization != null && authorization.startsWith(JWT_PREFIX.getValue())) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| return authorization.split(" ")[1]; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // 2. Cookie에서 JWT 추출 (웹) | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (request.getCookies() != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| for (Cookie cookie : request.getCookies()) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (JWT_HEADER_KEY.getValue().equals(cookie.getName())) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| return cookie.getValue(); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+78
to
+85
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chain쿠키에서 JWT 조회 시 키 상수 혼용 가능성 — 전용 쿠키 키 사용 검토 및 두 케이스 지원 현재 쿠키 이름 비교에 JWT_HEADER_KEY(통상 Authorization 헤더 키)를 재사용하고 있습니다. 일반적으로 쿠키 키는 헤더 키와 분리(JWT_COOKIE_KEY 등)하는 것이 명확합니다. 또한 쿠키 값에 "Bearer " 프리픽스가 포함될 가능성까지 대비해 제거 로직을 넣어두는 편이 안전합니다. 최소 보완(프리픽스 제거) 제안: - if (JWT_HEADER_KEY.getValue().equals(cookie.getName())) {
- return cookie.getValue();
- }
+ if (JWT_HEADER_KEY.getValue().equals(cookie.getName())) {
+ String value = cookie.getValue();
+ return value.startsWith(JWT_PREFIX.getValue())
+ ? value.substring(JWT_PREFIX.getValue().length()).trim()
+ : value;
+ }추가 권장:
레포 내 전용 쿠키 키 상수 존재 여부와 사용 위치 확인 스크립트: 🏁 Script executed: #!/bin/bash
# JWT 쿠키 관련 상수 및 사용처 탐색
rg -n "JWT_.*COOKIE" -S
rg -n "AuthParameters" -A 5 -B 3
# Authorization 헤더/쿠키 사용 패턴 확인
rg -n "JWT_HEADER_KEY"
# 쿠키 생성/추가 위치 탐색
rg -n 'new Cookie\(' -A 2
rg -n 'addCookie\(' -A 2Length of output: 10136 전용 JWT 쿠키 키 분리, Bearer 프리픽스 제거 및 보안 속성 추가 필요 현재 • 예시 변경안: src/main/java/konkuk/thip/common/security/constant/AuthParameters.java public enum AuthParameters {
JWT_HEADER_KEY("Authorization"),
JWT_PREFIX("Bearer "),
+ JWT_COOKIE_KEY("access_token"), // 원하는 쿠키 이름으로 변경
KAKAO("kakao"),
GOOGLE("google"),
KAKAO_PROVIDER_ID_KEY("id");
// …
}src/main/java/konkuk/thip/common/security/filter/JwtAuthenticationFilter.java - if (JWT_HEADER_KEY.getValue().equals(cookie.getName())) {
- String value = cookie.getValue();
- return value.startsWith(JWT_PREFIX.getValue())
- ? value.substring(JWT_PREFIX.getValue().length()).trim()
- : value;
- }
+ if (JWT_COOKIE_KEY.getValue().equals(cookie.getName())
+ || JWT_HEADER_KEY.getValue().equals(cookie.getName())) {
+ String value = cookie.getValue();
+ return value.startsWith(JWT_PREFIX.getValue())
+ ? value.substring(JWT_PREFIX.getValue().length()).trim()
+ : value;
+ }src/main/java/konkuk/thip/common/security/oauth2/CustomSuccessHandler.java - Cookie cookie = new Cookie(JWT_HEADER_KEY.getValue(), token);
+ Cookie cookie = new Cookie(JWT_COOKIE_KEY.getValue(), token);
+ cookie.setHttpOnly(true);
+ cookie.setSecure(true);
+ cookie.setPath("/");
+ // SameSite 설정이 필요할 경우 아래와 같이 직접 헤더를 조작
+ // response.setHeader("Set-Cookie",
+ // String.format("%s=%s; Path=/; Secure; HttpOnly; SameSite=Strict", cookie.getName(), cookie.getValue()));
response.addCookie(cookie);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||
| log.info("토큰이 없습니다."); | ||||||||||||||||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -6,6 +6,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import konkuk.thip.room.adapter.in.web.response.RoomPlayingDetailViewResponse; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import konkuk.thip.room.application.port.in.RoomShowPlayingDetailViewUseCase; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import konkuk.thip.room.application.port.out.RoomCommandPort; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import konkuk.thip.room.application.port.out.RoomQueryPort; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import konkuk.thip.room.domain.Room; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import konkuk.thip.room.application.port.out.RoomParticipantCommandPort; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import konkuk.thip.room.domain.RoomParticipants; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -24,14 +25,15 @@ public class RoomShowPlayingDetailViewService implements RoomShowPlayingDetailVi | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private static final int TOP_PARTICIPATION_VOTES_COUNT = 3; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final RoomCommandPort roomCommandPort; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final RoomQueryPort roomQueryPort; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final BookCommandPort bookCommandPort; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final RoomParticipantCommandPort roomParticipantCommandPort; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final VoteQueryPort voteQueryPort; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Transactional(readOnly = true) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public RoomPlayingDetailViewResponse getPlayingRoomDetailView(Long userId, Long roomId) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 1. Room 조회, Book 조회 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 1. Room 조회, Book 조회, Category와 연관된 Alias 조회 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Room room = roomCommandPort.getByIdOrThrow(roomId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Book book = bookCommandPort.findById(room.getBookId()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -66,6 +68,7 @@ private RoomPlayingDetailViewResponse buildResponse(Long userId, Room room, Book | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .currentPage(roomParticipants.getCurrentPageOfUser(userId)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .userPercentage(roomParticipants.getUserPercentageOfUser(userId)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .currentVotes(topParticipationVotes) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .categoryColor(roomQueryPort.findAliasColorOfCategory(room.getCategory())) // TODO : 리펙토링 대상 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 카테고리 색상 조회 위치 재검토 필요 현재 다음과 같이 서비스 메서드에서 미리 조회하는 것을 권장합니다: @Override
@Transactional(readOnly = true)
public RoomPlayingDetailViewResponse getPlayingRoomDetailView(Long userId, Long roomId) {
// 1. Room 조회, Book 조회, Category와 연관된 Alias 조회
Room room = roomCommandPort.getByIdOrThrow(roomId);
Book book = bookCommandPort.findById(room.getBookId());
+ String categoryColor = roomQueryPort.findAliasColorOfCategory(room.getCategory());
// 2. Room과 연관된 UserRoom 조회, RoomParticipants 일급 컬렉션 생성
// TODO. Room 도메인에 memberCount 값 추가된 후 리펙토링
List<RoomParticipant> findByRoomId = roomParticipantCommandPort.findAllByRoomId(roomId);
RoomParticipants roomParticipants = RoomParticipants.from(findByRoomId);
// 3. 투표 참여율이 가장 높은 투표 조회
List<RoomPlayingDetailViewResponse.CurrentVote> topParticipationVotes = voteQueryPort.findTopParticipationVotesByRoom(room, TOP_PARTICIPATION_VOTES_COUNT);
// 4. response 구성
- return buildResponse(userId, room, book, roomParticipants, topParticipationVotes);
+ return buildResponse(userId, room, book, roomParticipants, topParticipationVotes, categoryColor);
}
-private RoomPlayingDetailViewResponse buildResponse(Long userId, Room room, Book book, RoomParticipants roomParticipants, List<RoomPlayingDetailViewResponse.CurrentVote> topParticipationVotes) {
+private RoomPlayingDetailViewResponse buildResponse(Long userId, Room room, Book book, RoomParticipants roomParticipants, List<RoomPlayingDetailViewResponse.CurrentVote> topParticipationVotes, String categoryColor) {
return RoomPlayingDetailViewResponse.builder()
// ... 기존 필드들 ...
- .categoryColor(roomQueryPort.findAliasColorOfCategory(room.getCategory())) // TODO : 리펙토링 대상
+ .categoryColor(categoryColor)
.build();
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .build(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -53,27 +53,28 @@ private RoomRecruitingDetailViewResponse buildResponse( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RoomParticipants participants, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| List<RoomRecruitingDetailViewResponse.RecommendRoom> recommendRooms | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return new RoomRecruitingDetailViewResponse( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| participants.isHostOfRoom(userId), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| participants.isJoiningToRoom(userId), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| room.getId(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| room.getTitle(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| room.getCategory().getImageUrl(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| room.isPublic(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DateUtil.formatDate(room.getStartDate()), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DateUtil.formatDate(room.getEndDate()), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DateUtil.formatAfterTime(room.getStartDate()), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| room.getCategory().getValue(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| room.getDescription(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| participants.calculateMemberCount(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| room.getRecruitCount(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| book.getIsbn(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| book.getImageUrl(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| book.getTitle(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| book.getAuthorName(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| book.getDescription(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| book.getPublisher(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| recommendRooms | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return RoomRecruitingDetailViewResponse.builder() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .isHost(participants.isHostOfRoom(userId)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .isJoining(participants.isJoiningToRoom(userId)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .roomId(room.getId()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .roomName(room.getTitle()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .roomImageUrl(room.getCategory().getImageUrl()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .isPublic(room.isPublic()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .progressStartDate(DateUtil.formatDate(room.getStartDate())) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .progressEndDate(DateUtil.formatDate(room.getEndDate())) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .recruitEndDate(DateUtil.formatAfterTime(room.getStartDate())) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .category(room.getCategory().getValue()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .categoryColor(roomQueryPort.findAliasColorOfCategory(room.getCategory())) // TODO : 리펙토링 대상 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 카테고리 색상 조회 위치 개선 필요
서비스 메서드에서 미리 조회하도록 수정하세요: @Override
@Transactional(readOnly = true)
public RoomRecruitingDetailViewResponse getRecruitingRoomDetailView(Long userId, Long roomId) {
// 1. Room 조회, Book 조회
Room room = roomCommandPort.getByIdOrThrow(roomId);
Book book = bookCommandPort.findById(room.getBookId());
+ String categoryColor = roomQueryPort.findAliasColorOfCategory(room.getCategory());
// 2. Room과 연관된 UserRoom 조회, RoomParticipants 일급 컬렉션 생성
List<RoomParticipant> findByRoomId = roomParticipantCommandPort.findAllByRoomId(roomId);
RoomParticipants roomParticipants = RoomParticipants.from(findByRoomId);
// 3. 다른 모임방 추천
List<RoomRecruitingDetailViewResponse.RecommendRoom> recommendRooms = roomQueryPort.findOtherRecruitingRoomsByCategoryOrderByStartDateAsc(room, RECOMMEND_ROOM_COUNT);
// 4. response 구성
- return buildResponse(userId, room, book, roomParticipants, recommendRooms);
+ return buildResponse(userId, room, book, roomParticipants, recommendRooms, categoryColor);
}
private RoomRecruitingDetailViewResponse buildResponse(
Long userId,
Room room,
Book book,
RoomParticipants participants,
- List<RoomRecruitingDetailViewResponse.RecommendRoom> recommendRooms
+ List<RoomRecruitingDetailViewResponse.RecommendRoom> recommendRooms,
+ String categoryColor
) {
return RoomRecruitingDetailViewResponse.builder()
// ... 기존 필드들 ...
- .categoryColor(roomQueryPort.findAliasColorOfCategory(room.getCategory())) // TODO : 리펙토링 대상
+ .categoryColor(categoryColor)
// ... 나머지 필드들 ...
.build();
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .roomDescription(room.getDescription()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .memberCount(participants.calculateMemberCount()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .recruitCount(room.getRecruitCount()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .isbn(book.getIsbn()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .bookImageUrl(book.getImageUrl()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .bookTitle(book.getTitle()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .authorName(book.getAuthorName()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .bookDescription(book.getDescription()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .publisher(book.getPublisher()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .recommendRooms(recommendRooms) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .build(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Authorization 헤더 파싱 취약 — split 인덱싱으로 AIOOB 가능
"Bearer" 다음에 공백/토큰이 없거나 공백이 여러 개인 경우 ArrayIndexOutOfBoundsException 가능성이 있습니다. prefix 길이 기반으로 안전하게 파싱하세요.
적용 제안:
📝 Committable suggestion
🤖 Prompt for AI Agents