Skip to content

Commit 867bad9

Browse files
NADELYSShodoon
authored andcommitted
refactor: 로그인 관리자와 일반으로 분리 (BACKEND-17)
Co-authored-by: DoHoon Yoon <[email protected]>
1 parent 3e98c2d commit 867bad9

File tree

5 files changed

+135
-1
lines changed

5 files changed

+135
-1
lines changed

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

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package dmu.dasom.api.domain.member.controller;
22

33
import dmu.dasom.api.domain.common.exception.ErrorResponse;
4+
import dmu.dasom.api.domain.member.dto.LoginRequestDto;
45
import dmu.dasom.api.domain.member.dto.SignupRequestDto;
56
import dmu.dasom.api.domain.member.service.MemberService;
67
import dmu.dasom.api.global.auth.dto.TokenBox;
@@ -49,6 +50,68 @@ public ResponseEntity<Void> signUp(@Valid @RequestBody final SignupRequestDto re
4950
return ResponseEntity.ok().build();
5051
}
5152

53+
// 일반 사용자 로그인
54+
@Operation(summary = "일반 사용자 로그인")
55+
@ApiResponses(value = {
56+
@ApiResponse(responseCode = "200", description = "로그인 성공 (Header로 토큰 반환)"),
57+
@ApiResponse(responseCode = "400", description = "실패 케이스",
58+
content = @Content(
59+
mediaType = "application/json",
60+
schema = @Schema(implementation = ErrorResponse.class),
61+
examples = {
62+
@ExampleObject(
63+
name = "회원 없음",
64+
value = "{ \"code\": \"C003\", \"message\": \"해당 회원을 찾을 수 없습니다.\" }"
65+
),
66+
@ExampleObject(
67+
name = "로그인 실패",
68+
value = "{ \"code\": \"C005\", \"message\": \"로그인에 실패하였습니다.\" }"
69+
),
70+
@ExampleObject(
71+
name = "권한 없음",
72+
value = "{ \"code\": \"C001\", \"message\": \"인증되지 않은 사용자입니다.\" }")}))})
73+
@PostMapping("/auth/user-login")
74+
public ResponseEntity<Void> userLogin(@Valid @RequestBody final LoginRequestDto request) {
75+
final TokenBox tokenBox = memberService.userLogin(request);
76+
final HttpHeaders headers = new HttpHeaders();
77+
headers.add("Access-Token", tokenBox.getAccessToken());
78+
headers.add("Refresh-Token", tokenBox.getRefreshToken());
79+
headers.add("Authority", tokenBox.getAuthority());
80+
81+
return ResponseEntity.ok().headers(headers).build();
82+
}
83+
84+
// 관리자 로그인
85+
@Operation(summary = "관리자 로그인")
86+
@ApiResponses(value = {
87+
@ApiResponse(responseCode = "200", description = "로그인 성공 (Header로 토큰 반환)"),
88+
@ApiResponse(responseCode = "400", description = "실패 케이스",
89+
content = @Content(
90+
mediaType = "application/json",
91+
schema = @Schema(implementation = ErrorResponse.class),
92+
examples = {
93+
@ExampleObject(
94+
name = "회원 없음",
95+
value = "{ \"code\": \"C003\", \"message\": \"해당 회원을 찾을 수 없습니다.\" }"
96+
),
97+
@ExampleObject(
98+
name = "로그인 실패",
99+
value = "{ \"code\": \"C005\", \"message\": \"로그인에 실패하였습니다.\" }"
100+
),
101+
@ExampleObject(
102+
name = "권한 없음",
103+
value = "{ \"code\": \"C001\", \"message\": \"인증되지 않은 사용자입니다.\" }")}))})
104+
@PostMapping("/auth/admin-login")
105+
public ResponseEntity<Void> adminLogin(@Valid @RequestBody final LoginRequestDto request) {
106+
final TokenBox tokenBox = memberService.adminLogin(request);
107+
final HttpHeaders headers = new HttpHeaders();
108+
headers.add("Access-Token", tokenBox.getAccessToken());
109+
headers.add("Refresh-Token", tokenBox.getRefreshToken());
110+
headers.add("Authority", tokenBox.getAuthority());
111+
112+
return ResponseEntity.ok().headers(headers).build();
113+
}
114+
52115
@Operation(summary = "토큰 갱신")
53116
@ApiResponses(value = {
54117
@ApiResponse(responseCode = "200", description = "토큰 갱신 성공 (Header로 토큰 반환)"),
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package dmu.dasom.api.domain.member.dto;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import jakarta.validation.constraints.Email;
5+
import jakarta.validation.constraints.NotNull;
6+
import jakarta.validation.constraints.Size;
7+
import lombok.Getter;
8+
9+
@Getter
10+
@Schema(name = "LoginRequestDto", description = "로그인 요청 DTO")
11+
public class LoginRequestDto {
12+
13+
@NotNull(message = "이메일은 필수 값입니다.")
14+
@Email(message = "유효한 이메일 주소를 입력해주세요.")
15+
@Size(max = 64)
16+
@Schema(description = "이메일 주소", example = "[email protected]")
17+
private String email;
18+
19+
@NotNull(message = "비밀번호는 필수 값입니다.")
20+
@Size(min = 8, max = 20, message = "비밀번호는 8자 이상 20자 이하로 입력해주세요.")
21+
@Schema(description = "비밀번호", example = "password123!")
22+
private String password;
23+
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package dmu.dasom.api.domain.member.service;
22

3+
import dmu.dasom.api.domain.member.dto.LoginRequestDto;
34
import dmu.dasom.api.domain.member.dto.SignupRequestDto;
45
import dmu.dasom.api.domain.member.entity.Member;
56
import dmu.dasom.api.global.auth.dto.TokenBox;
@@ -13,6 +14,12 @@ public interface MemberService {
1314

1415
void signUp(final SignupRequestDto request);
1516

17+
TokenBox login(final LoginRequestDto request);
18+
19+
TokenBox userLogin(final LoginRequestDto request);
20+
21+
TokenBox adminLogin(final LoginRequestDto request);
22+
1623
TokenBox tokenRotation(final UserDetailsImpl userDetails);
1724

1825
}

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
package dmu.dasom.api.domain.member.service;
22

3+
import dmu.dasom.api.domain.member.dto.LoginRequestDto;
34
import dmu.dasom.api.domain.common.exception.CustomException;
45
import dmu.dasom.api.domain.common.exception.ErrorCode;
56
import dmu.dasom.api.domain.recruit.service.RecruitService;
67
import dmu.dasom.api.domain.member.dto.SignupRequestDto;
78
import dmu.dasom.api.domain.member.entity.Member;
9+
import dmu.dasom.api.domain.member.enums.Role;
810
import dmu.dasom.api.domain.member.repository.MemberRepository;
911
import dmu.dasom.api.global.auth.dto.TokenBox;
1012
import dmu.dasom.api.global.auth.jwt.JwtUtil;
1113
import dmu.dasom.api.global.auth.userdetails.UserDetailsImpl;
14+
import dmu.dasom.api.domain.common.exception.CustomException;
15+
import dmu.dasom.api.domain.common.exception.ErrorCode;
1216
import lombok.RequiredArgsConstructor;
1317
import org.springframework.security.core.GrantedAuthority;
1418
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@@ -56,6 +60,43 @@ public void signUp(final SignupRequestDto request) {
5660
memberRepository.save(request.toEntity(encoder.encode(request.getPassword()), generation));
5761
}
5862

63+
// 로그인 (기존 로직을 private 헬퍼 메소드로 변경)
64+
private TokenBox authenticateAndGenerateToken(final String email, final String password, final Role expectedRole) {
65+
// 1. 이메일로 사용자 조회
66+
final Member member = memberRepository.findByEmail(email)
67+
.orElseThrow(() -> new CustomException(ErrorCode.MEMBER_NOT_FOUND));
68+
69+
// 2. 비밀번호 일치 여부 확인
70+
if (!encoder.matches(password, member.getPassword())) {
71+
throw new CustomException(ErrorCode.LOGIN_FAILED);
72+
}
73+
74+
// 3. 역할 확인
75+
if (expectedRole != null && member.getRole() != expectedRole) {
76+
throw new CustomException(ErrorCode.UNAUTHORIZED); // 또는 더 구체적인 에러 코드
77+
}
78+
79+
// 4. JWT 토큰 생성 및 반환
80+
return jwtUtil.generateTokenBox(member.getEmail(), member.getRole().getName());
81+
}
82+
83+
@Override
84+
public TokenBox login(final LoginRequestDto request) {
85+
// 이 메소드는 더 이상 사용되지 않거나, userLogin/adminLogin으로 대체됩니다.
86+
// 여기서는 임시로 일반 로그인으로 처리합니다.
87+
return authenticateAndGenerateToken(request.getEmail(), request.getPassword(), null);
88+
}
89+
90+
@Override
91+
public TokenBox userLogin(final LoginRequestDto request) {
92+
return authenticateAndGenerateToken(request.getEmail(), request.getPassword(), Role.ROLE_MEMBER);
93+
}
94+
95+
@Override
96+
public TokenBox adminLogin(final LoginRequestDto request) {
97+
return authenticateAndGenerateToken(request.getEmail(), request.getPassword(), Role.ROLE_ADMIN);
98+
}
99+
59100
// 토큰 갱신
60101
@Override
61102
public TokenBox tokenRotation(final UserDetailsImpl userDetails) {

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
@@ -73,7 +73,7 @@ public SecurityFilterChain filterChain(final HttpSecurity http, final Authentica
7373
.requestMatchers("/api/auth/logout", "/api/auth/rotation").authenticated()
7474
.anyRequest().permitAll())
7575
.addFilterBefore(jwtFilter, CustomAuthenticationFilter.class)
76-
.addFilterAt(customAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
76+
7777
.addFilterAfter(new CustomLogoutFilter(jwtUtil), JwtFilter.class)
7878
.exceptionHandling(handler -> handler
7979
.accessDeniedHandler(accessDeniedHandler)

0 commit comments

Comments
 (0)