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

관리자 기능 백엔드 구현 #780

Merged
merged 89 commits into from
Feb 3, 2024
Merged
Show file tree
Hide file tree
Changes from 70 commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
96e1287
feat: spring-boot-starter-security 추가
LJW25 Jan 19, 2024
d149c76
chore: Flyway AdminMember 테이블 추가
LJW25 Jan 19, 2024
8cea490
feat: AdminAuth 어노테이션 구현
LJW25 Jan 19, 2024
d256694
feat: AdminLoginArgumentResolver 구현
LJW25 Jan 19, 2024
9341f48
feat: AdminException 추가
LJW25 Jan 19, 2024
e8a0e4b
feat: AdminMember 구현
LJW25 Jan 19, 2024
e834830
test: AdminLoginControllerTest 작성
LJW25 Jan 19, 2024
13719d2
feat: AdminLogin API 구현
LJW25 Jan 19, 2024
b42233c
test: AdminServiceTest 작성
LJW25 Jan 19, 2024
6c1bf63
feat: AdminService 구현
LJW25 Jan 19, 2024
fa168e0
test: AdminMemberControllerTest 구현
LJW25 Jan 20, 2024
1f04c65
feat: AdminOnly 어노테이션 구현
LJW25 Jan 20, 2024
319e1f1
feat: AdminMember API 구현
LJW25 Jan 20, 2024
637f942
test: AdminMemberServiceTest 작성
LJW25 Jan 20, 2024
7b1fd0f
feat: AdminMemberService 구현
LJW25 Jan 20, 2024
c6a74af
chore: submodule 업데이트
LJW25 Jan 20, 2024
3da90f9
feat: city 상세 목록 조회 기능 구현
LJW25 Jan 20, 2024
4808192
test: city 상세 목록 조회 테스트 작성
LJW25 Jan 20, 2024
540fd63
test: city 추가 테스트 작성
LJW25 Jan 20, 2024
3989c14
feat: city 추가 기능 구현
LJW25 Jan 20, 2024
a41517e
test: city 수정 기능 테스트 작성
LJW25 Jan 20, 2024
700ba71
feat: city 수정 기능 구현
LJW25 Jan 20, 2024
e002a84
test: city 상세 목록 조회 API 테스트 작성
LJW25 Jan 20, 2024
e80aedd
feat: city 상세 목록 조회 API 구현
LJW25 Jan 20, 2024
a696b33
feat: 도시 추가 API 구현
LJW25 Jan 20, 2024
adacf8c
test: 도시 추가 API 테스트 작성
LJW25 Jan 20, 2024
6eaf012
test: 도시 수정 API 테스트 작성
LJW25 Jan 20, 2024
b44580f
feat: 도시 수정 API 구현
LJW25 Jan 20, 2024
9397c14
test: 카테고리 세부 정보 조회 기능 테스트 작성
LJW25 Jan 20, 2024
8c78c40
feat: 카테고리 세부 정보 조회 기능 구현
LJW25 Jan 20, 2024
b19a32c
rename: category response dto 패키지 이동
LJW25 Jan 20, 2024
0ac1231
test: 카테고리 추가 기능 테스트 작성
LJW25 Jan 20, 2024
f887d59
feat: 카테고리 추가 기능 구현
LJW25 Jan 20, 2024
9d668f7
test: 카테고리 수정 기능 테스트 작성
LJW25 Jan 20, 2024
281d0cc
feat: 카테고리 수정 기능 구현
LJW25 Jan 20, 2024
98fd96c
test: 카테고리 세부 정보 API 테스트 작성
LJW25 Jan 20, 2024
47e4d08
feat: 카테고리 세부 정보 API 구현
LJW25 Jan 20, 2024
afb2e94
test: 카테고리 추가 API 테스트 작성
LJW25 Jan 20, 2024
02d375d
feat: 카테고리 추가 API 구현
LJW25 Jan 20, 2024
b98d7f1
test: 카테고리 수정 API 테스트 작성
LJW25 Jan 20, 2024
3ae8de8
feat: 카테고리 수정 API 구현
LJW25 Jan 20, 2024
8e3fe70
test: 환율 페이징 조회 기능 테스트 작성
LJW25 Jan 20, 2024
29c05aa
feat: 환율 페이징 조회 기능 구현
LJW25 Jan 20, 2024
e43fa33
fix: 환율 조회 repository 메소드 수정
LJW25 Jan 20, 2024
679a1a2
test: 환율 조회 Api 테스트 작성
LJW25 Jan 20, 2024
cd51552
feat: 환율 조회 Api 구현
LJW25 Jan 20, 2024
3a0752a
rename: Currency dto 패키지 이동
LJW25 Jan 20, 2024
161a904
test: 환율 저장 기능 테스트 작성
LJW25 Jan 20, 2024
18583b3
feat: 환율 저장 기능 구현
LJW25 Jan 20, 2024
9614be7
test: 환율 수정 기능 테스트 작성
LJW25 Jan 20, 2024
cc6a8b7
feat: 환율 수정 기능 구현
LJW25 Jan 20, 2024
5457d43
test: 환율 생성 API 테스트 작성
LJW25 Jan 20, 2024
238889d
feat: 환율 생성 API 구현
LJW25 Jan 20, 2024
8fd59f6
test: 환율 수정 API 테스트 작성
LJW25 Jan 20, 2024
b59b43e
feat: 환율 수정 API 구현
LJW25 Jan 20, 2024
beb7351
test: 공백 제거
LJW25 Jan 20, 2024
47809f6
chore: submodule 업데이트
LJW25 Jan 20, 2024
cecb6f6
chore: 라이브러리 변경
LJW25 Jan 22, 2024
5db7c03
refactor: BCrypt 라이브러리 변경
LJW25 Jan 22, 2024
6abd773
chore: 서브모듈 업데이트
LJW25 Jan 23, 2024
ca62ca7
refactor: AdminMemberRepository 메소드 이름 변경
LJW25 Jan 23, 2024
6e78496
refactor: Master static import 변경
LJW25 Jan 23, 2024
0edb405
refactor: 패키지명 오타 수정
LJW25 Jan 23, 2024
c7d9cb8
refactor: 패키지 이동
LJW25 Jan 23, 2024
1bdf8e2
test: AdminMemberService 통합 테스트 작성
LJW25 Jan 23, 2024
5aa99bd
test: AdminLoginService 통합 테스트 작성
LJW25 Jan 23, 2024
531eedf
refactor: Category 생성, 수정 시 id를 포함하도록 변경
LJW25 Jan 23, 2024
e4aae46
test: CategoryService 통합 테스트 작성
LJW25 Jan 23, 2024
531e2b8
test: CityService 통합 테스트 작성
LJW25 Jan 23, 2024
34cf691
test: AdminMember 생성 Controller 통합 테스트 작성
LJW25 Jan 23, 2024
ebc37a4
test: AdminCurrency 생성,조회 Controller 통합 테스트 작성
LJW25 Jan 23, 2024
fe4e5ca
refactor: userName을 username으로 변경
LJW25 Jan 23, 2024
d429a5a
refactor: request 검증 메세지 수정
LJW25 Jan 23, 2024
bedc68c
refactor: Currency 조회 메소드 이름 변경
LJW25 Jan 23, 2024
e4b5941
refactor: response 변수 이름 변경
LJW25 Jan 23, 2024
e7bece6
refactor: 불필요한 생성자 제거
LJW25 Jan 23, 2024
af24938
chore: 패키지 버전 변경
LJW25 Jan 23, 2024
d997a8d
refactor: 컨벤션 맞춤
LJW25 Jan 24, 2024
1a12237
refactor: response 생성자 private 접근제어 추가
LJW25 Jan 24, 2024
114cd24
refactor: category 중복 제거 로직 변경
LJW25 Jan 24, 2024
8a374bb
refactor: currency 중복 검증 메소드 변경
LJW25 Jan 24, 2024
c899d7a
refactor: username 변수명 수정
LJW25 Jan 30, 2024
f5cc040
refactor: username 변수명 수정
LJW25 Jan 30, 2024
78d696b
refactor: AdminLoginArgumentResolver 로직 변경
LJW25 Jan 30, 2024
bf38a58
refactor: Enum 개행 추가
LJW25 Jan 30, 2024
6e61d2c
docs: Restdocs 추가
LJW25 Jan 30, 2024
3438afd
refactor: 카테고리 한글명 중복 검증 제거
LJW25 Feb 3, 2024
5df3614
refactor: 환율 request dto krw 삭제
LJW25 Feb 3, 2024
81bde6d
Merge branch 'develop' of https://github.com/woowacourse-teams/2023-h…
LJW25 Feb 3, 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
2 changes: 1 addition & 1 deletion backend/backend-submodule
2 changes: 2 additions & 0 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ dependencies {

implementation 'org.flywaydb:flyway-core'
implementation 'org.flywaydb:flyway-mysql'

implementation group: 'org.mindrot', name: 'jbcrypt', version: '0.3m'
Copy link
Collaborator

Choose a reason for hiding this comment

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

0.4이전 버전 취약점 경고뜨는데, 0.4로 바꾸는 건 어떤가요?
0.4도 호환 잘되는 것 같습니다!

Suggested change
implementation group: 'org.mindrot', name: 'jbcrypt', version: '0.3m'
implementation 'org.mindrot:jbcrypt:0.4'

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

감사합니다 너무 좋아요 너무 깔끔해

}

test {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package hanglog.admin;

import static hanglog.admin.domain.type.AdminType.MASTER;
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.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));

if (adminMemberRepository.existsByIdAndAdminType(memberId, MASTER)) {
return Accessor.master(memberId);
}
return Accessor.admin(memberId);
Copy link
Collaborator

Choose a reason for hiding this comment

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

adminMember를 조회하는 이 부분만 현재 LoginArgumentResolver랑의 차이점 같은데, 따로 구현하신 이유가 있을까요 ?! memberId가 admin이랑 일반 user랑 겹칠 수 있어서 .. ? 구분할 방법이 없어서 사용하셨다면
if (parameter.hasParameterAnnotation(AdminAuth.class)) 를 통해 구분하는 방법은 어떤가요 ?!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

이 부분은 슬랙을 통해 말씀드린 내용 그대로! 다른 백엔드분들 의견 모이는대로 반영하겠습니다.

}

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());
}
Comment on lines +92 to +95
Copy link
Collaborator

@hgo641 hgo641 Jan 22, 2024

Choose a reason for hiding this comment

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

refreshTokenRepository 일반 유저 리프레시토큰 저장용으로 만든거라, 잘하면 어드민이 아니라 일반 유저의 토큰으로 로그인 시도했을 때 Authority.ADMIN으로 로그인이 돼버릴지도?..

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

배포시에 일반 행록과 admin 행록의 도메인이 다를 것이기 때문에 캐시도 따로 저장되서, 해당 문제는 발생하지 않습니다!

Copy link
Collaborator

Choose a reason for hiding this comment

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

도메인 다르면 같은 레디스 사용해도 캐시 따로 저장돼요?! 진짜 몰랐음

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

앗 아니 레디스에는 똑같이 적용 되는데, 브라우저에서 캐시가 다르게 저장되기 때문에 hanglog.com에 관리자 페이지 캐시로 접근할 수 는 없다는 의미였습니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

검증 시 Admin, master id 인지 검증 하는 로직 추가했습니다!

}
19 changes: 19 additions & 0 deletions backend/src/main/java/hanglog/admin/AdminLoginResolverConfig.java
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);
}
}
14 changes: 14 additions & 0 deletions backend/src/main/java/hanglog/admin/SecurityConfig.java
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();
}
Comment on lines +9 to +13
Copy link
Member

Choose a reason for hiding this comment

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

BCrypt 말고 다른 기본 단방향 암호화 알고리즘으로는 어떤 문제가 있었나요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

다른 방법들을 예시로 들자면

  • PBKDF2 (Password-Based Key Derivation Function 2) : 반복 횟수를 조절하여 성능과 보안 수준을 조절할 수 있다는 장점이 있지만, BCrypt에 비해 GPU를 이용한 공격에 더 취약하고 설정에 따라 성능 저하가 발생할 수 있다는 단점이 있음.
  • Argon2: 최신 알고리즘으로 메모리와 CPU 사용을 동시에 조절하여 더 나은 보안성 제공함. 하지만 상대적으로 새로운 알고리즘이기 때문에 다른 알고리즘보다 검증된 시간이 짧고, 자료가 적음.
  • SHA-256: 널리 알려져 있고, 많이 사용되며 구현하기 쉬움. 하지만 단순한 해시 함수이기 때문에 빠른 계산 속도가 오히려 단점으로 작용함 (무차별 대입 공격에 취약).
  • SCrypt: 메모리 집약적 해싱 방식을 사용하여 GPU 공격에 강함. 하지만 메모리 요구량이 높을 수 있으며, 구현이 복잡할 수 있음.

요약하자면 BCrypt가 많은 케이스를 통해 검증된 방식이고, 자료가 많아 개발 시간이 단축되며, 구현 방식 또한 단순하다는 것이 결정에 가장 크게 작용한 요인입니다!

Copy link
Member

Choose a reason for hiding this comment

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

결국 BCrypt를 사용하기 위해 스프링 시큐리티를 적용한 거라면 너무 과도한 의존성 추가가 아닐까 싶네요..!
어떠한 프레임워크를 추가하는게 생각보다 꽤 복잡한 추가 설정과 에러 대응이 필요할 수도 있거든요(특히 시큐리티는 더!)

간단하게 BCypt 라이브러리만 추가하는게 어떠신지....!

https://jj-yi.tistory.com/22

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

5db7c03

반영하였습니다! 저도 그부분이 걸렸지만 방법을 못찾았었는데, 디노 짱짱입니다. 덕분에 불필요하게 exclude 하던 서브모듈 또한 변경하였습니다. 감사합니다👍

}
70 changes: 70 additions & 0 deletions backend/src/main/java/hanglog/admin/domain/AdminMember.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package hanglog.admin.domain;

import static jakarta.persistence.EnumType.STRING;
import static jakarta.persistence.GenerationType.IDENTITY;
import static lombok.AccessLevel.PROTECTED;

import hanglog.admin.domain.type.AdminType;
import hanglog.member.domain.MemberState;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import java.time.LocalDateTime;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;

@Entity
@Getter
@NoArgsConstructor(access = PROTECTED)
@SQLDelete(sql = "UPDATE admin_member SET status = 'DELETED' WHERE id = ?")
Copy link
Collaborator

Choose a reason for hiding this comment

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

오 AdminUser에 soft delete가 필요하다고 생각하신 이유가 궁금해요!
전 AdminUser를 삭제했다가 복원해야할 상황이 생길지 의문이었어요. 삭제된 AdminUser에 대해서 특별한 통계가 필요할 것 같지도 않아서 hard delete해도 되겠다고 생각했었습니다. 물론 AdminUser를 만들어본 적이 없는 짧은 식견입니다 헷

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

저도 고민했던 내용인데요! 사실 Soft Delete와 Hard Delete 모두 크게 차이가 나는 장단점이 없다가 결론이었습니다!

저희 시스템 규모에서 AdminUser는 진짜 많아져 봐야 100개가 안될 데이터라서, 성능적으로 비교하는건 의미가 적겠더라구요.
그래서 결국 낮은 확률이라도 대비할 수 있는 상황이 많고, 기록의 의미도 담을 수 있도록 Soft Delete로 구현하였습니다.

@Where(clause = "status = 'ACTIVE'")
public class AdminMember {

@Id
@GeneratedValue(strategy = IDENTITY)
private Long id;

@Column(nullable = false, unique = true, length = 20)
private String userName;

@Column(nullable = false, length = 64)
private String password;

@Column(nullable = false)
private LocalDateTime lastLoginDate;

@Column(nullable = false)
@Enumerated(value = STRING)
private AdminType adminType;

@Enumerated(value = STRING)
private MemberState status;

@CreatedDate
@Column(updatable = false)
private LocalDateTime createdAt;

@LastModifiedDate
private LocalDateTime modifiedAt;

public AdminMember(final Long id, final String userName, final String password, final AdminType adminType) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

위 아래 생성자 정팩메 사용하면 더 좋을지도 ㅎㅎ
현재 Member랑 동일한 로직인거 같은데, 수정하는 로직에서 createdAt도 LocalDateTime.now()로 변경되면 안될거 가타요 ㅎㅎ 물론 @Column(updatable = false) 있어서 변경되지 않을거 같지만 .. !!!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

오 그러네요?!?! 근데 Member는 createdAt 어떻게 유지되고 있는거죠..?!

this.id = id;
this.userName = userName;
this.password = password;
this.lastLoginDate = LocalDateTime.now();
this.adminType = adminType;
this.status = MemberState.ACTIVE;
this.createdAt = LocalDateTime.now();
this.modifiedAt = LocalDateTime.now();
}

public AdminMember(final String userName, final String password, final AdminType adminType) {
this(null, userName, password, adminType);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package hanglog.admin.domain.repository;

import hanglog.admin.domain.AdminMember;
import hanglog.admin.domain.type.AdminType;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;

public interface AdminMemberRepository extends JpaRepository<AdminMember, Long> {

Optional<AdminMember> findByUserName(String userName);

Boolean existsByIdAndAdminType(Long id, AdminType adminType);

Boolean existsByUserName(String userName);
}
17 changes: 17 additions & 0 deletions backend/src/main/java/hanglog/admin/domain/type/AdminType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package hanglog.admin.domain.type;

import static hanglog.global.exception.ExceptionCode.NULL_ADMIN_AUTHORITY;

import hanglog.global.exception.AdminException;
import java.util.Arrays;

public enum AdminType {
ADMIN, MASTER;
Copy link
Collaborator

Choose a reason for hiding this comment

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

저희 이넘 첫 줄 개행 한것도 있고 안한것도 있던데 이것도 클래스니까 개행합니까? (trip패키지의 이넘들은 개행되어 있는데 auth는 안되어있음)

Suggested change
public enum AdminType {
ADMIN, MASTER;
public enum AdminType {
ADMIN,
MASTER;

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

일단 AdminType은 Auth랑 같은 방식을 따르는게 맞는것 같아서 개행을 안했었는데, Trip까지 전부 보니까 Auth가 잘못되있었던것도 같구요..? 둘 모두 개행 하는 쪽으로 수정하였습니다.


public static AdminType getMappedAdminType(final String adminType) {
return Arrays.stream(values())
.filter(value -> value.name().toUpperCase().equals(adminType))
.findAny()
.orElseThrow(() -> new AdminException(NULL_ADMIN_AUTHORITY));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package hanglog.admin.dto.request;

import static lombok.AccessLevel.PRIVATE;

import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@AllArgsConstructor
@NoArgsConstructor(access = PRIVATE)
Copy link
Collaborator

Choose a reason for hiding this comment

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

@NoArgsConstructor 사용하지않는 생성자인 것 같은데, 추가한 이유가 있나요?

public class AdminLoginRequest {

@NotNull(message = "사용자 이름을 입력해주세요.")
@Size(max = 20, message = "사용자 이름은 20자를 초과할 수 없습니다.")
private String userName;

@NotNull(message = "비밀번호를 입력해주세요.")
@Size(min = 4, max = 20, message = "비밀번호는 4자 이상, 20자 이하여야 합니다.")
private String password;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package hanglog.admin.dto.request;


import static lombok.AccessLevel.PRIVATE;

import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@AllArgsConstructor
@NoArgsConstructor(access = PRIVATE)
public class AdminMemberCreateRequest {

@NotNull(message = "사용자 이름을 입력해주세요.")
@Size(max = 20, message = "사용자 이름은 20자를 초과할 수 없습니다.")
private String userName;

@NotNull(message = "비밀번호를 입력해주세요.")
@Size(min = 4, max = 20, message = "비밀번호는 4자 이상, 20자 이하여야 합니다.")
private String password;
Comment on lines +17 to +19
Copy link
Collaborator

Choose a reason for hiding this comment

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

얘 DB랑 max 조건 다른 이유 있나요?.? 궁금

Copy link
Collaborator

Choose a reason for hiding this comment

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

암호화해서 저장하면 길이가 달라져서 그런거 같타요
bcrypt 암호화 결과 길이가 정해져있나용 .. ? 최대 20자라고 가정했을 때 64자가 최대인가요 ?!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

비밀번호 암호화하면서 60자로 늘어나기 때문입니다!


@NotNull(message = "관리자 권한을 선택해 주세요.")
private String adminType;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package hanglog.admin.dto.request;


import static lombok.AccessLevel.PRIVATE;

import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@AllArgsConstructor
@NoArgsConstructor(access = PRIVATE)
public class PasswordUpdateRequest {

@NotNull(message = "기존 비밀번호를 입력해주세요.")
@Size(min = 4, max = 20, message = "비밀번호는 4자 이상, 20자 이하여야 합니다.")
private String currentPassword;

@NotNull(message = "새로운 비밀번호를 입력해주세요.")
@Size(min = 4, max = 20, message = "비밀번호는 4자 이상, 20자 이하여야 합니다.")
private String newPassword;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package hanglog.admin.dto.response;

import hanglog.admin.domain.AdminMember;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public class AdminMemberResponse {

private final Long id;
private final String userName;
Copy link
Collaborator

Choose a reason for hiding this comment

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

혹시 ... username이 더 익숙하지않으신가요?
ㅋㅋㅋㅋ아... 근데 DB 까지 바꿔야하겠군요 변경 리소스가 작다면,,, 호옥시 username 가능한가요? 물론 중요한 건 아니니 편하게 반영해주십시오 갓이오좌...

Copy link
Collaborator

Choose a reason for hiding this comment

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

ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 나도 username이 좋아 헤헤 ..

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

반영 완!

Copy link
Member

Choose a reason for hiding this comment

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

'userName'

private final String adminType;

public static AdminMemberResponse from(final AdminMember adminMember) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

생성자 private으로 막아놓고 정팩메만 사용하면 좋을거 같아요 ~~!
다른 dto들도 보이면 바꿔주시면 🙇‍♂️🙇‍♂️

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

1a12237

return new AdminMemberResponse(
adminMember.getId(),
adminMember.getUserName(),
adminMember.getAdminType().name()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package hanglog.admin.infrastructure;

import org.mindrot.jbcrypt.BCrypt;

public class BCryptPasswordEncoder implements PasswordEncoder {
@Override
public String encode(final String password) {
return BCrypt.hashpw(password, BCrypt.gensalt());
}

@Override
public boolean matches(final String password, final String hashed) {
return BCrypt.checkpw(password, hashed);
}
Comment on lines +6 to +14
Copy link
Collaborator

Choose a reason for hiding this comment

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

오 생각보다 굉장히 간단하게 구현할 수 있군요 .. !

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package hanglog.admin.infrastructure;

public interface PasswordEncoder {
String encode(String password);

boolean matches(String password, String hashed);
}
Loading