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

feat : admin - 관리자 로그인 기능 추가 #141 #142

Merged
merged 20 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b2268ba
refactor : createManager 메서드 제거
oownahcohc Sep 30, 2023
3d78475
feat : Admin NotFound 예외 클래스
oownahcohc Oct 2, 2023
827ac91
feat : Password Mismatch 예외 클래스
oownahcohc Oct 2, 2023
31cddf6
feat : Password Encoder 설정
oownahcohc Oct 2, 2023
4581379
feat : Admin 엔티티 클래스
oownahcohc Oct 2, 2023
76f98db
feat : Role enum 클래스
oownahcohc Oct 2, 2023
37afec8
feat : JpaRepository 를 확정한 AdminRepository
oownahcohc Oct 2, 2023
1bb5126
feat : AdminAuthUseCase 인터페이스
oownahcohc Oct 2, 2023
9a6bf5a
feat : AdminLoginRequest DTO 클래스
oownahcohc Oct 2, 2023
439647f
feat : AdminAuthUseCase 인터페이스를 구현한 AdminAuthService
oownahcohc Oct 2, 2023
158af86
feat : AdminJwtManagePort 아웃고잉 포트 인터페이스
oownahcohc Oct 2, 2023
6881a83
feat : AdminJwtManagePort 아웃고잉 포트 인터페이스를 구현한 AdminJwtManageAdapter
oownahcohc Oct 2, 2023
69d8681
feat : AdminTokenResponse DTO 클래스
oownahcohc Oct 2, 2023
2bcfc3e
feat : PasswordManagePort 아웃고잉 포트 인터페이스
oownahcohc Oct 2, 2023
1eef9aa
feat : PasswordManagePort 아웃고잉 포트 인터페이스를 구현한 PasswordManageAdapte
oownahcohc Oct 2, 2023
3f8ce56
feat : AdminLoginRequest
oownahcohc Oct 2, 2023
3885dee
feat : AdminLoginResponse
oownahcohc Oct 2, 2023
26c1840
feat : AdminAuthManageController
oownahcohc Oct 2, 2023
f3eb9f7
add : getter 추가
oownahcohc Oct 2, 2023
03195ea
test : AdminAuthService test
oownahcohc Oct 2, 2023
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
24 changes: 24 additions & 0 deletions src/main/java/backend/wal/admin/adapter/AdminJwtManageAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package backend.wal.admin.adapter;

import backend.wal.admin.application.port.out.AdminTokenResponseDto;
import backend.wal.admin.application.port.out.AdminJwtManagePort;
import backend.wal.auth.adapter.jwt.JwtManagerAdapter;
import org.springframework.stereotype.Component;

@Component
public class AdminJwtManageAdapter implements AdminJwtManagePort {

private final JwtManagerAdapter jwtManagerAdapter;

public AdminJwtManageAdapter(final JwtManagerAdapter jwtManagerAdapter) {
this.jwtManagerAdapter = jwtManagerAdapter;
}

@Override
public AdminTokenResponseDto createToken(Long adminId) {
return new AdminTokenResponseDto(
jwtManagerAdapter.createAccessToken(adminId),
jwtManagerAdapter.getAccessTokenExpiresIn()
);
}
}
25 changes: 25 additions & 0 deletions src/main/java/backend/wal/admin/adapter/PasswordManageAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package backend.wal.admin.adapter;

import backend.wal.admin.application.port.out.PasswordManagePort;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

@Component
public class PasswordManageAdapter implements PasswordManagePort {

private final PasswordEncoder passwordEncoder;

public PasswordManageAdapter(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}

@Override
public String encode(String password) {
return passwordEncoder.encode(password);
}

@Override
public boolean isMatch(String requestPassword, String savedPassword) {
return passwordEncoder.matches(requestPassword, savedPassword);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package backend.wal.admin.application.port.in;

public interface AdminAuthUseCase {

void create(AdminLoginRequestDto requestDto);

Long login(AdminLoginRequestDto requestDto);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package backend.wal.admin.application.port.in;

public class AdminLoginRequestDto {

private final String email;
private final String password;

public AdminLoginRequestDto(String email, String password) {
this.email = email;
this.password = password;
}

public String getEmail() {
return email;
}

public String getPassword() {
return password;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package backend.wal.admin.application.port.out;

public interface AdminJwtManagePort {
AdminTokenResponseDto createToken(Long adminId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package backend.wal.admin.application.port.out;

public class AdminTokenResponseDto {

private final String token;
private final Long expiredIn;

public AdminTokenResponseDto(String token, Long expiredIn) {
this.token = token;
this.expiredIn = expiredIn;
}

public String getToken() {
return token;
}

public Long getExpiredIn() {
return expiredIn;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package backend.wal.admin.application.port.out;

public interface PasswordManagePort {

String encode(String password);

boolean isMatch(String requestPassword, String savedPassword);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package backend.wal.admin.application.service;

import backend.wal.admin.application.port.in.AdminAuthUseCase;
import backend.wal.admin.application.port.in.AdminLoginRequestDto;
import backend.wal.admin.application.port.out.PasswordManagePort;
import backend.wal.admin.domain.aggregate.Admin;
import backend.wal.admin.domain.repository.AdminRepository;
import backend.wal.admin.exception.NotFoundAdminException;
import backend.wal.admin.exception.UnAuthorizedPasswordException;
import backend.wal.support.annotation.AppService;
import org.springframework.transaction.annotation.Transactional;

@AppService
public class AdminAuthService implements AdminAuthUseCase {

private final AdminRepository adminRepository;
private final PasswordManagePort passwordManagePort;

public AdminAuthService(final AdminRepository adminRepository, final PasswordManagePort passwordManagePort) {
this.adminRepository = adminRepository;
this.passwordManagePort = passwordManagePort;
}

@Override
@Transactional
public void create(AdminLoginRequestDto requestDto) {
adminRepository.save(new Admin(
requestDto.getEmail(),
passwordManagePort.encode(requestDto.getPassword())
));
}

@Override
@Transactional(readOnly = true)
public Long login(AdminLoginRequestDto requestDto) {
Admin admin = findExistAdminByEmail(requestDto.getEmail());
validateMatchPassword(requestDto.getPassword(), admin.getPassword());
return admin.getId();
}

private Admin findExistAdminByEmail(String email) {
return adminRepository.findByEmail(email)
.orElseThrow(() -> NotFoundAdminException.notExists(email));
}

private void validateMatchPassword(String requestPassword, String adminPassword) {
if (!passwordManagePort.isMatch(requestPassword, adminPassword)) {
throw UnAuthorizedPasswordException.wrong();
}
}
}
15 changes: 15 additions & 0 deletions src/main/java/backend/wal/admin/config/PasswordEncoderConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package backend.wal.admin.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class PasswordEncoderConfig {

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
46 changes: 46 additions & 0 deletions src/main/java/backend/wal/admin/domain/aggregate/Admin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package backend.wal.admin.domain.aggregate;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.time.LocalDateTime;

@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@EntityListeners(AuditingEntityListener.class)
public class Admin {

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

@Column(nullable = false, length = 50)
private String email;

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

@Enumerated(EnumType.STRING)
@Column(nullable = false, length = 10)
private Role role;

@CreatedDate
private LocalDateTime createdAt;

public Admin(final String email, final String password) {
this.email = email;
this.password = password;
this.role = Role.ADMIN;
}

public Long getId() {
return id;
}

public String getPassword() {
return password;
}
}
13 changes: 13 additions & 0 deletions src/main/java/backend/wal/admin/domain/aggregate/Role.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package backend.wal.admin.domain.aggregate;

public enum Role {

ADMIN("관리자"),
;

private final String value;

Role(String value) {
this.value = value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package backend.wal.admin.domain.repository;

import backend.wal.admin.domain.aggregate.Admin;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface AdminRepository extends JpaRepository<Admin, Long> {
Optional<Admin> findByEmail(String email);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package backend.wal.admin.exception;

import backend.wal.advice.exception.NotFoundException;

public class NotFoundAdminException extends NotFoundException {

public NotFoundAdminException(String message) {
super(message);
}

public static NotFoundAdminException notExists(String email) {
return new NotFoundAdminException(String.format("존재하지 않는 관리자 계정 (%s) 입니다", email));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package backend.wal.admin.exception;

import backend.wal.advice.exception.UnAuthorizedException;

public class UnAuthorizedPasswordException extends UnAuthorizedException {

public UnAuthorizedPasswordException(String message) {
super(message);
}

public static UnAuthorizedPasswordException wrong() {
return new UnAuthorizedPasswordException("비밀번호가 일치하지 않습니다");
}
}
47 changes: 47 additions & 0 deletions src/main/java/backend/wal/admin/web/AdminAuthManageController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package backend.wal.admin.web;

import backend.wal.admin.application.port.in.AdminAuthUseCase;
import backend.wal.admin.application.port.out.AdminJwtManagePort;
import backend.wal.admin.application.port.out.AdminTokenResponseDto;
import backend.wal.admin.web.dto.AdminLoginRequest;
import backend.wal.admin.web.dto.AdminLoginResponse;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

import static backend.wal.support.utils.HttpHeaderUtils.AUTHORIZATION;
import static backend.wal.support.utils.HttpHeaderUtils.withBearerToken;

@RestController
@RequestMapping("/admin/auth")
public class AdminAuthManageController {

private final AdminAuthUseCase adminAuthUseCase;
private final AdminJwtManagePort adminJwtManagePort;

public AdminAuthManageController(final AdminAuthUseCase adminAuthUseCase,
final AdminJwtManagePort adminJwtManagePort) {
this.adminAuthUseCase = adminAuthUseCase;
this.adminJwtManagePort = adminJwtManagePort;
}

@PostMapping("/create")
public ResponseEntity<Void> create(@Valid @RequestBody AdminLoginRequest request) {
adminAuthUseCase.create(request.toServiceDto());
return ResponseEntity.status(HttpStatus.CREATED).build();
}

@PostMapping("/login")
public ResponseEntity<AdminLoginResponse> login(@Valid @RequestBody AdminLoginRequest request) {
Long adminId = adminAuthUseCase.login(request.toServiceDto());
AdminTokenResponseDto responseDto = adminJwtManagePort.createToken(adminId);
return ResponseEntity.ok()
.header(AUTHORIZATION, withBearerToken(responseDto.getToken()))
.body(new AdminLoginResponse(responseDto.getExpiredIn()));
}
}
25 changes: 25 additions & 0 deletions src/main/java/backend/wal/admin/web/dto/AdminLoginRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package backend.wal.admin.web.dto;

import backend.wal.admin.application.port.in.AdminLoginRequestDto;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;

public class AdminLoginRequest {

@NotBlank
private String email;

@NotBlank
@Pattern(regexp = "(?=.*[0-9])(?=.*[a-zA-Z])(?=.*\\W)(?=\\S+$).{8,40}")
private String password;

public AdminLoginRequest(String email, String password) {
this.email = email;
this.password = password;
}

public AdminLoginRequestDto toServiceDto() {
return new AdminLoginRequestDto(email, password);
}
}
14 changes: 14 additions & 0 deletions src/main/java/backend/wal/admin/web/dto/AdminLoginResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package backend.wal.admin.web.dto;

public class AdminLoginResponse {

private final Long expiredIn;

public AdminLoginResponse(Long expiredIn) {
this.expiredIn = expiredIn;
}

public Long getExpiredIn() {
return expiredIn;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,8 @@ public Long getLoginUserIdFromAccessToken(String accessToken) {
.getBody();
return payload.get(JWT_CLAIM_NAME, Long.class);
}

public long getAccessTokenExpiresIn() {
return accessTokenExpiresIn;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,6 @@ public static User createGeneral(final CreateUserDto createUserDto) {
);
}

public static User createManager(final String nickname, final String socialId, SocialType socialType) {
return new User(nickname, SocialInfo.of(socialId, socialType), UserStatus.ACTIVE, UserRole.ADMIN);
}

public void changeNickname(String nickname) {
this.nickname = nickname;
}
Expand Down
Loading