Skip to content

Commit 88c2033

Browse files
committed
[fix/#9] parsing 예외, NotFound 예외 BadCredentialsException로 통일 및 이메일 검증 로직 추가
1 parent 44e718d commit 88c2033

File tree

6 files changed

+95
-27
lines changed

6 files changed

+95
-27
lines changed

build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ dependencies {
5353
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
5454
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
5555

56+
// validator
57+
implementation 'commons-validator:commons-validator:1.7'
58+
5659
}
5760

5861
tasks.named('test') {

src/main/java/com/moplus/moplus_server/domain/member/domain/Member.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,8 @@ public Member(String nickname, String email, String password, MemberRole role) {
3535
this.password = password;
3636
this.role = role;
3737
}
38+
39+
public boolean isMatchingPassword(String password) {
40+
return this.password.equals(password);
41+
}
3842
}

src/main/java/com/moplus/moplus_server/global/config/security/SecurityConfig.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public AuthenticationManager authenticationManager(AuthenticationConfiguration c
8989

9090
@Bean
9191
public EmailPasswordAuthenticationProvider emailPasswordAuthenticationProvider() {
92-
return new EmailPasswordAuthenticationProvider(memberService, bCryptPasswordEncoder());
92+
return new EmailPasswordAuthenticationProvider(memberService);
9393
}
9494

9595
@Bean

src/main/java/com/moplus/moplus_server/global/security/filter/EmailPasswordAuthenticationFilter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
import com.fasterxml.jackson.databind.ObjectMapper;
44
import com.moplus.moplus_server.domain.auth.dto.request.AdminLoginRequest;
55
import com.moplus.moplus_server.global.error.exception.ErrorCode;
6-
import com.moplus.moplus_server.global.error.exception.NotFoundException;
76
import jakarta.servlet.http.HttpServletRequest;
87
import jakarta.servlet.http.HttpServletResponse;
98
import java.io.IOException;
109
import org.springframework.security.authentication.AuthenticationManager;
10+
import org.springframework.security.authentication.BadCredentialsException;
1111
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
1212
import org.springframework.security.core.Authentication;
1313
import org.springframework.security.core.AuthenticationException;
@@ -29,7 +29,7 @@ public Authentication attemptAuthentication(HttpServletRequest request, HttpServ
2929
authRequest = UsernamePasswordAuthenticationToken.unauthenticated(loginRequest.email(),
3030
loginRequest.password());
3131
} catch (IOException exception) {
32-
throw new NotFoundException(ErrorCode.MEMBER_NOT_FOUND);
32+
throw new BadCredentialsException(ErrorCode.INVALID_INPUT_VALUE.getMessage());
3333
}
3434
setDetails(request, authRequest);
3535
return this.getAuthenticationManager().authenticate(authRequest);

src/main/java/com/moplus/moplus_server/global/security/provider/EmailPasswordAuthenticationProvider.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,38 @@
22

33
import com.moplus.moplus_server.domain.member.domain.Member;
44
import com.moplus.moplus_server.domain.member.service.MemberService;
5+
import com.moplus.moplus_server.global.error.exception.ErrorCode;
56
import java.util.List;
67
import lombok.RequiredArgsConstructor;
8+
import org.apache.commons.validator.routines.EmailValidator;
79
import org.springframework.security.authentication.AuthenticationProvider;
810
import org.springframework.security.authentication.BadCredentialsException;
911
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
1012
import org.springframework.security.core.Authentication;
1113
import org.springframework.security.core.AuthenticationException;
1214
import org.springframework.security.core.authority.SimpleGrantedAuthority;
13-
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
1415

1516
@RequiredArgsConstructor
1617
public class EmailPasswordAuthenticationProvider implements AuthenticationProvider {
1718

1819
private final MemberService memberService;
19-
private final BCryptPasswordEncoder passwordEncoder;
20+
21+
private static void validateEmail(String memberEmail) {
22+
if (!EmailValidator.getInstance().isValid(memberEmail)) {
23+
throw new BadCredentialsException(ErrorCode.BAD_CREDENTIALS.getMessage());
24+
}
25+
}
2026

2127
@Override
2228
public Authentication authenticate(final Authentication authentication) throws AuthenticationException {
2329
final UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;
2430
final String memberEmail = token.getName();
2531
final String memberPassword = (String) token.getCredentials();
2632

27-
Member member = memberService.getMemberByEmail(memberEmail);
28-
if (!memberPassword.equals(member.getPassword())) {
29-
throw new BadCredentialsException(member.getEmail() + "Invalid password");
33+
validateEmail(memberEmail);
34+
final Member member = getMemberByEmail(memberEmail);
35+
if (!member.isMatchingPassword(memberPassword)) {
36+
throw new BadCredentialsException(ErrorCode.BAD_CREDENTIALS.getMessage());
3037
}
3138

3239
return UsernamePasswordAuthenticationToken.authenticated(
@@ -36,6 +43,14 @@ public Authentication authenticate(final Authentication authentication) throws A
3643
));
3744
}
3845

46+
private Member getMemberByEmail(String memberEmail) {
47+
try {
48+
return memberService.getMemberByEmail(memberEmail);
49+
} catch (Exception e) {
50+
throw new BadCredentialsException(ErrorCode.BAD_CREDENTIALS.getMessage());
51+
}
52+
}
53+
3954
@Override
4055
public boolean supports(Class<?> authentication) {
4156
return authentication.equals(UsernamePasswordAuthenticationToken.class);

src/test/java/com/moplus/moplus_server/domain/auth/controller/AuthControllerTest.java

Lines changed: 65 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
import com.fasterxml.jackson.databind.ObjectMapper;
88
import com.moplus.moplus_server.domain.auth.dto.request.AdminLoginRequest;
99
import org.junit.jupiter.api.BeforeEach;
10+
import org.junit.jupiter.api.Nested;
1011
import org.junit.jupiter.api.Test;
12+
import org.junit.jupiter.params.ParameterizedTest;
13+
import org.junit.jupiter.params.provider.ValueSource;
1114
import org.springframework.beans.factory.annotation.Autowired;
1215
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
1316
import org.springframework.boot.test.context.SpringBootTest;
@@ -41,30 +44,73 @@ public void setMockMvc() {
4144
.apply(springSecurity()).build();
4245
}
4346

44-
@Test
45-
void 어드민_로그인_성공() throws Exception {
47+
@Nested
48+
class 어드민_로그인 {
4649

47-
AdminLoginRequest request = new AdminLoginRequest("admin@example.com", "password123"); // DTO 객체 생성
48-
String requestBody = objectMapper.writeValueAsString(request);
50+
@Test
51+
void 성공() throws Exception {
4952

50-
mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/auth/admin/login")
51-
.contentType("application/json")
52-
.content(requestBody))
53-
.andExpect(status().isOk()) // 200 응답 확인
54-
.andExpect(header().exists("Authorization"))
55-
.andExpect(header().exists("RefreshToken"));
53+
AdminLoginRequest request = new AdminLoginRequest("admin@example.com", "password123");
54+
String requestBody = objectMapper.writeValueAsString(request);
5655

57-
}
56+
mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/auth/admin/login")
57+
.contentType("application/json")
58+
.content(requestBody))
59+
.andExpect(status().isOk()) // 200 응답 확인
60+
.andExpect(header().exists("Authorization"))
61+
.andExpect(header().exists("RefreshToken"));
62+
63+
}
64+
65+
@Test
66+
void 잘못된_요청_본문() throws Exception {
67+
68+
record TempRecord(String data) {
69+
}
70+
71+
TempRecord request = new TempRecord("임시 테스트 요청 본문");
72+
String requestBody = objectMapper.writeValueAsString(request);
73+
74+
mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/auth/admin/login")
75+
.contentType("application/json")
76+
.content(requestBody))
77+
.andExpect(status().isUnauthorized());
78+
}
79+
80+
@ParameterizedTest
81+
@ValueSource(strings = {
82+
"plainaddress", // 이메일 형식이 아님
83+
"@missingusername.com", // 사용자명 없음
84+
"username@.com", // 도메인 이름 없음
85+
"username@com", // 잘못된 도메인
86+
"username@domain..com", // 연속된 점
87+
"username@domain,com", // 쉼표 포함
88+
"username@domain space.com", // 공백 포함
89+
"username@domain.com space", // 공백 포함
90+
"username@domain#com", // 특수문자 포함
91+
"" // 빈 문자열
92+
})
93+
void 잘못된_이메일_양식(String email) throws Exception {
94+
95+
AdminLoginRequest request = new AdminLoginRequest(email, "password123");
96+
String requestBody = objectMapper.writeValueAsString(request);
97+
98+
mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/auth/admin/login")
99+
.contentType("application/json")
100+
.content(requestBody))
101+
.andExpect(status().isUnauthorized()); // 401 응답 확인
102+
}
58103

59-
@Test
60-
void 어드민_로그인_실패() throws Exception {
104+
@Test
105+
void 실패() throws Exception {
61106

62-
AdminLoginRequest request = new AdminLoginRequest("admin@example.com", "wrong123"); // DTO 객체 생성
63-
String requestBody = objectMapper.writeValueAsString(request);
107+
AdminLoginRequest request = new AdminLoginRequest("admin@example.com", "wrong123");
108+
String requestBody = objectMapper.writeValueAsString(request);
64109

65-
mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/auth/admin/login")
66-
.contentType("application/json")
67-
.content(requestBody))
68-
.andExpect(status().isUnauthorized()); // 401 응답 확인
110+
mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/auth/admin/login")
111+
.contentType("application/json")
112+
.content(requestBody))
113+
.andExpect(status().isUnauthorized()); // 401 응답 확인
114+
}
69115
}
70116
}

0 commit comments

Comments
 (0)