-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: spring-boot-starter-security 추가 * chore: Flyway AdminMember 테이블 추가 * feat: AdminAuth 어노테이션 구현 * feat: AdminLoginArgumentResolver 구현 * feat: AdminException 추가 * feat: AdminMember 구현 * test: AdminLoginControllerTest 작성 * feat: AdminLogin API 구현 * test: AdminServiceTest 작성 * feat: AdminService 구현 * test: AdminMemberControllerTest 구현 * feat: AdminOnly 어노테이션 구현 * feat: AdminMember API 구현 * test: AdminMemberServiceTest 작성 * feat: AdminMemberService 구현 * chore: submodule 업데이트 * feat: city 상세 목록 조회 기능 구현 * test: city 상세 목록 조회 테스트 작성 * test: city 추가 테스트 작성 * feat: city 추가 기능 구현 * test: city 수정 기능 테스트 작성 * feat: city 수정 기능 구현 * test: city 상세 목록 조회 API 테스트 작성 * feat: city 상세 목록 조회 API 구현 * feat: 도시 추가 API 구현 * test: 도시 추가 API 테스트 작성 * test: 도시 수정 API 테스트 작성 * feat: 도시 수정 API 구현 * test: 카테고리 세부 정보 조회 기능 테스트 작성 * feat: 카테고리 세부 정보 조회 기능 구현 * rename: category response dto 패키지 이동 * test: 카테고리 추가 기능 테스트 작성 * feat: 카테고리 추가 기능 구현 * test: 카테고리 수정 기능 테스트 작성 * feat: 카테고리 수정 기능 구현 * test: 카테고리 세부 정보 API 테스트 작성 * feat: 카테고리 세부 정보 API 구현 * test: 카테고리 추가 API 테스트 작성 * feat: 카테고리 추가 API 구현 * test: 카테고리 수정 API 테스트 작성 * feat: 카테고리 수정 API 구현 * test: 환율 페이징 조회 기능 테스트 작성 * feat: 환율 페이징 조회 기능 구현 * fix: 환율 조회 repository 메소드 수정 * test: 환율 조회 Api 테스트 작성 * feat: 환율 조회 Api 구현 * rename: Currency dto 패키지 이동 * test: 환율 저장 기능 테스트 작성 * feat: 환율 저장 기능 구현 * test: 환율 수정 기능 테스트 작성 * feat: 환율 수정 기능 구현 * test: 환율 생성 API 테스트 작성 * feat: 환율 생성 API 구현 * test: 환율 수정 API 테스트 작성 * feat: 환율 수정 API 구현 * test: 공백 제거 * chore: submodule 업데이트 * chore: 라이브러리 변경 * refactor: BCrypt 라이브러리 변경 * chore: 서브모듈 업데이트 * refactor: AdminMemberRepository 메소드 이름 변경 * refactor: Master static import 변경 * refactor: 패키지명 오타 수정 * refactor: 패키지 이동 * test: AdminMemberService 통합 테스트 작성 * test: AdminLoginService 통합 테스트 작성 * refactor: Category 생성, 수정 시 id를 포함하도록 변경 * test: CategoryService 통합 테스트 작성 * test: CityService 통합 테스트 작성 * test: AdminMember 생성 Controller 통합 테스트 작성 * test: AdminCurrency 생성,조회 Controller 통합 테스트 작성 * refactor: userName을 username으로 변경 * refactor: request 검증 메세지 수정 * refactor: Currency 조회 메소드 이름 변경 * refactor: response 변수 이름 변경 * refactor: 불필요한 생성자 제거 * chore: 패키지 버전 변경 * refactor: 컨벤션 맞춤 * refactor: response 생성자 private 접근제어 추가 * refactor: category 중복 제거 로직 변경 * refactor: currency 중복 검증 메소드 변경 * refactor: username 변수명 수정 * refactor: username 변수명 수정 * refactor: AdminLoginArgumentResolver 로직 변경 * refactor: Enum 개행 추가 * docs: Restdocs 추가 * refactor: 카테고리 한글명 중복 검증 제거 * refactor: 환율 request dto krw 삭제
- Loading branch information
Showing
83 changed files
with
3,911 additions
and
69 deletions.
There are no files selected for viewing
Submodule backend-submodule
updated
from a0ae21 to cc3201
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,196 @@ | ||
= HangLog | ||
:toc: left | ||
:source-highlighter: highlightjs | ||
:sectlinks: | ||
|
||
[[overview-http-status-codes]] | ||
=== HTTP status codes | ||
|
||
|=== | ||
| 상태 코드 | 설명 | ||
|
||
| `200 OK` | ||
| 성공 | ||
|
||
| `201 Created` | ||
| 리소스 생성 | ||
|
||
| `204 NO_CONTENT` | ||
| 성공 후 반환 값 없음 | ||
|
||
| `400 Bad Request` | ||
| 잘못된 요청 | ||
|
||
| `401 Unauthorized` | ||
| 비인증 상태 | ||
|
||
| `403 Forbidden` | ||
| 권한 거부 | ||
|
||
| `404 Not Found` | ||
| 존재하지 않는 요청 리소스 | ||
|
||
| `500 Internal Server Error` | ||
| 서버 에러 | ||
|=== | ||
|
||
=== Exception codes | ||
[[exception-codes]] | ||
include::{snippets}/exception-code-controller-test/get-exception-codes/exception-response-fields.adoc[] | ||
|
||
== 관리자 로그인 API | ||
|
||
=== 로그인 (POST /admin/login) | ||
|
||
==== 요청 | ||
include::{snippets}/admin-login-controller-test/login/http-request.adoc[] | ||
include::{snippets}/admin-login-controller-test/login/request-fields.adoc[] | ||
|
||
==== 응답 | ||
include::{snippets}/admin-login-controller-test/login/http-response.adoc[] | ||
include::{snippets}/admin-login-controller-test/login/response-fields.adoc[] | ||
|
||
=== 토큰 재발급 (POST /admin/token) | ||
|
||
==== 요청 | ||
include::{snippets}/admin-login-controller-test/extend-login/http-request.adoc[] | ||
요청 쿠키 | ||
include::{snippets}/admin-login-controller-test/extend-login/request-cookies.adoc[] | ||
|
||
==== 응답 | ||
include::{snippets}/admin-login-controller-test/extend-login/http-response.adoc[] | ||
include::{snippets}/admin-login-controller-test/extend-login/response-fields.adoc[] | ||
|
||
=== 로그아웃 (DELETE /admin/logout) | ||
|
||
==== 요청 | ||
include::{snippets}/admin-login-controller-test/logout/http-request.adoc[] | ||
요청 헤더 | ||
include::{snippets}/admin-login-controller-test/logout/request-headers.adoc[] | ||
요청 쿠키 | ||
include::{snippets}/admin-login-controller-test/logout/request-cookies.adoc[] | ||
|
||
==== 응답 | ||
include::{snippets}/admin-login-controller-test/logout/http-response.adoc[] | ||
|
||
|
||
== 관리자 멤버 관리 API | ||
|
||
=== 관리자 멤버 목록 조회 (GET /admin/members) | ||
|
||
==== 요청 | ||
include::{snippets}/admin-member-controller-test/get-admin-members/http-request.adoc[] | ||
|
||
==== 응답 | ||
include::{snippets}/admin-member-controller-test/get-admin-members/http-response.adoc[] | ||
include::{snippets}/admin-member-controller-test/get-admin-members/response-fields.adoc[] | ||
|
||
=== 관리자 멤버 생성 (POST /admin/members) | ||
|
||
==== 요청 | ||
include::{snippets}/admin-member-controller-test/create-admin-member/http-request.adoc[] | ||
include::{snippets}/admin-member-controller-test/create-admin-member/request-fields.adoc[] | ||
|
||
==== 응답 | ||
include::{snippets}/admin-member-controller-test/create-admin-member/http-response.adoc[] | ||
|
||
=== 관리자 멤버 비밀번호 수정 (PATCH /admin/members/:memberId/password) | ||
|
||
==== 요청 | ||
include::{snippets}/admin-member-controller-test/update-password/http-request.adoc[] | ||
include::{snippets}/admin-member-controller-test/update-password/path-parameters.adoc[] | ||
include::{snippets}/admin-member-controller-test/update-password/request-fields.adoc[] | ||
|
||
==== 응답 | ||
include::{snippets}/admin-member-controller-test/update-password/http-response.adoc[] | ||
|
||
== 도시 관리 API | ||
|
||
=== 도시 목록 조회 (GET /admin/cities) | ||
|
||
==== 요청 | ||
include::{snippets}/admin-city-controller-test/get-cities-detail/http-request.adoc[] | ||
|
||
==== 응답 | ||
include::{snippets}/admin-city-controller-test/get-cities-detail/http-response.adoc[] | ||
include::{snippets}/admin-city-controller-test/get-cities-detail/response-fields.adoc[] | ||
|
||
=== 도시 생성 (POST /admin/cities) | ||
|
||
==== 요청 | ||
include::{snippets}/admin-city-controller-test/create-city/http-request.adoc[] | ||
include::{snippets}/admin-city-controller-test/create-city/request-fields.adoc[] | ||
|
||
==== 응답 | ||
include::{snippets}/admin-city-controller-test/create-city/http-response.adoc[] | ||
|
||
=== 도시 수정 (PUT /admin/cities/:citiId) | ||
|
||
==== 요청 | ||
include::{snippets}/admin-city-controller-test/update-city/http-request.adoc[] | ||
include::{snippets}/admin-city-controller-test/update-city/path-parameters.adoc[] | ||
include::{snippets}/admin-city-controller-test/update-city/request-fields.adoc[] | ||
|
||
==== 응답 | ||
include::{snippets}/admin-city-controller-test/update-city/http-response.adoc[] | ||
|
||
|
||
== 카테고리 관리 API | ||
|
||
=== 카테고리 목록 조회 (GET /admin/categories) | ||
|
||
==== 요청 | ||
include::{snippets}/admin-category-controller-test/get-categories-detail/http-request.adoc[] | ||
|
||
==== 응답 | ||
include::{snippets}/admin-category-controller-test/get-categories-detail/http-response.adoc[] | ||
include::{snippets}/admin-category-controller-test/get-categories-detail/response-fields.adoc[] | ||
|
||
=== 카테고리 생성 (POST /admin/categories) | ||
|
||
==== 요청 | ||
include::{snippets}/admin-category-controller-test/create-category/http-request.adoc[] | ||
include::{snippets}/admin-category-controller-test/create-category/request-fields.adoc[] | ||
|
||
==== 응답 | ||
include::{snippets}/admin-category-controller-test/create-category/http-response.adoc[] | ||
|
||
=== 카테고리 수정 (PUT /admin/categories/:categoryId) | ||
|
||
==== 요청 | ||
include::{snippets}/admin-category-controller-test/update-category/http-request.adoc[] | ||
include::{snippets}/admin-category-controller-test/update-category/path-parameters.adoc[] | ||
include::{snippets}/admin-category-controller-test/update-category/request-fields.adoc[] | ||
|
||
==== 응답 | ||
include::{snippets}/admin-category-controller-test/update-category/http-response.adoc[] | ||
|
||
== 환율 관리 API | ||
|
||
=== 환율 목록 페이지 조회 (GET /admin/currencies) | ||
|
||
==== 요청 | ||
include::{snippets}/admin-currency-controller-test/get-currencies-detail/http-request.adoc[] | ||
|
||
==== 응답 | ||
include::{snippets}/admin-currency-controller-test/get-currencies-detail/http-response.adoc[] | ||
include::{snippets}/admin-currency-controller-test/get-currencies-detail/response-fields.adoc[] | ||
|
||
=== 환율 생성 (POST /admin/currencies) | ||
|
||
==== 요청 | ||
include::{snippets}/admin-currency-controller-test/create-currency/http-request.adoc[] | ||
include::{snippets}/admin-currency-controller-test/create-currency/request-fields.adoc[] | ||
|
||
==== 응답 | ||
include::{snippets}/admin-currency-controller-test/create-currency/http-response.adoc[] | ||
|
||
=== 환율 수정 (PUT /admin/currencies/:currencyId) | ||
|
||
==== 요청 | ||
include::{snippets}/admin-currency-controller-test/update-currency/http-request.adoc[] | ||
include::{snippets}/admin-currency-controller-test/update-currency/path-parameters.adoc[] | ||
include::{snippets}/admin-currency-controller-test/update-currency/request-fields.adoc[] | ||
|
||
==== 응답 | ||
include::{snippets}/admin-currency-controller-test/update-currency/http-response.adoc[] |
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
96 changes: 96 additions & 0 deletions
96
backend/src/main/java/hanglog/admin/AdminLoginArgumentResolver.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 hanglog.admin; | ||
|
||
import static hanglog.admin.domain.type.AdminType.ADMIN; | ||
import static hanglog.admin.domain.type.AdminType.MASTER; | ||
import static hanglog.global.exception.ExceptionCode.INVALID_ADMIN_AUTHORITY; | ||
import static hanglog.global.exception.ExceptionCode.INVALID_REQUEST; | ||
import static hanglog.global.exception.ExceptionCode.NOT_FOUND_REFRESH_TOKEN; | ||
import static org.springframework.http.HttpHeaders.AUTHORIZATION; | ||
|
||
import hanglog.admin.domain.AdminMember; | ||
import hanglog.admin.domain.repository.AdminMemberRepository; | ||
import hanglog.auth.AdminAuth; | ||
import hanglog.auth.domain.Accessor; | ||
import hanglog.global.exception.BadRequestException; | ||
import hanglog.global.exception.RefreshTokenException; | ||
import hanglog.login.domain.MemberTokens; | ||
import hanglog.login.domain.repository.RefreshTokenRepository; | ||
import hanglog.login.infrastructure.BearerAuthorizationExtractor; | ||
import hanglog.login.infrastructure.JwtProvider; | ||
import jakarta.servlet.http.Cookie; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import java.util.Arrays; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.core.MethodParameter; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.web.bind.support.WebDataBinderFactory; | ||
import org.springframework.web.context.request.NativeWebRequest; | ||
import org.springframework.web.method.support.HandlerMethodArgumentResolver; | ||
import org.springframework.web.method.support.ModelAndViewContainer; | ||
|
||
@RequiredArgsConstructor | ||
@Component | ||
public class AdminLoginArgumentResolver implements HandlerMethodArgumentResolver { | ||
|
||
private static final String REFRESH_TOKEN = "refresh-token"; | ||
|
||
private final JwtProvider jwtProvider; | ||
|
||
private final BearerAuthorizationExtractor extractor; | ||
|
||
private final RefreshTokenRepository refreshTokenRepository; | ||
|
||
private final AdminMemberRepository adminMemberRepository; | ||
|
||
@Override | ||
public boolean supportsParameter(final MethodParameter parameter) { | ||
return parameter.withContainingClass(Long.class) | ||
.hasParameterAnnotation(AdminAuth.class); | ||
} | ||
|
||
@Override | ||
public Accessor resolveArgument( | ||
final MethodParameter parameter, | ||
final ModelAndViewContainer mavContainer, | ||
final NativeWebRequest webRequest, | ||
final WebDataBinderFactory binderFactory | ||
) { | ||
final HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); | ||
if (request == null) { | ||
throw new BadRequestException(INVALID_REQUEST); | ||
} | ||
|
||
final String refreshToken = extractRefreshToken(request.getCookies()); | ||
final String accessToken = extractor.extractAccessToken(webRequest.getHeader(AUTHORIZATION)); | ||
jwtProvider.validateTokens(new MemberTokens(refreshToken, accessToken)); | ||
|
||
final Long memberId = Long.valueOf(jwtProvider.getSubject(accessToken)); | ||
|
||
final AdminMember adminMember = adminMemberRepository.findById(memberId) | ||
.orElseThrow(() -> new RefreshTokenException(INVALID_ADMIN_AUTHORITY)); | ||
|
||
if (adminMember.getAdminType().equals(MASTER)) { | ||
return Accessor.master(memberId); | ||
} | ||
if (adminMember.getAdminType().equals(ADMIN)) { | ||
return Accessor.admin(memberId); | ||
} | ||
throw new RefreshTokenException(INVALID_ADMIN_AUTHORITY); | ||
} | ||
|
||
private String extractRefreshToken(final Cookie... cookies) { | ||
if (cookies == null) { | ||
throw new RefreshTokenException(NOT_FOUND_REFRESH_TOKEN); | ||
} | ||
return Arrays.stream(cookies) | ||
.filter(this::isValidRefreshToken) | ||
.findFirst() | ||
.orElseThrow(() -> new RefreshTokenException(NOT_FOUND_REFRESH_TOKEN)) | ||
.getValue(); | ||
} | ||
|
||
private boolean isValidRefreshToken(final Cookie cookie) { | ||
return REFRESH_TOKEN.equals(cookie.getName()) && | ||
refreshTokenRepository.existsById(cookie.getValue()); | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
backend/src/main/java/hanglog/admin/AdminLoginResolverConfig.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,19 @@ | ||
package hanglog.admin; | ||
|
||
import java.util.List; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.web.method.support.HandlerMethodArgumentResolver; | ||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | ||
|
||
@Configuration | ||
@RequiredArgsConstructor | ||
public class AdminLoginResolverConfig implements WebMvcConfigurer { | ||
|
||
private final AdminLoginArgumentResolver adminLoginArgumentResolver; | ||
|
||
@Override | ||
public void addArgumentResolvers(final List<HandlerMethodArgumentResolver> resolvers) { | ||
resolvers.add(adminLoginArgumentResolver); | ||
} | ||
} |
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,14 @@ | ||
package hanglog.admin; | ||
|
||
import hanglog.admin.infrastructure.BCryptPasswordEncoder; | ||
import hanglog.admin.infrastructure.PasswordEncoder; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
@Configuration | ||
public class SecurityConfig { | ||
@Bean | ||
public PasswordEncoder passwordEncoder() { | ||
return new BCryptPasswordEncoder(); | ||
} | ||
} |
Oops, something went wrong.