Skip to content

Commit d6e1562

Browse files
committed
[250331]-Users : 토큰기능 추가 / 유저정보 validation / 유닛테스트
1 parent 676c608 commit d6e1562

File tree

13 files changed

+272
-26
lines changed

13 files changed

+272
-26
lines changed

build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,17 @@ dependencies {
2626
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
2727
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
2828
implementation 'org.springframework.boot:spring-boot-starter-web'
29+
implementation 'io.jsonwebtoken:jjwt-api:0.12.6'
30+
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.6'
31+
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.6' // JSON 처리를 위한 의존성
2932
compileOnly 'org.projectlombok:lombok'
33+
testCompileOnly 'org.projectlombok:lombok'
3034
developmentOnly 'org.springframework.boot:spring-boot-devtools'
3135
runtimeOnly 'com.mysql:mysql-connector-j'
3236
annotationProcessor 'org.projectlombok:lombok'
3337
testImplementation 'org.springframework.boot:spring-boot-starter-test'
3438
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
39+
implementation 'com.google.code.gson:gson'
3540
}
3641

3742
tasks.named('test') {

src/main/java/com/ecommerce/member/dto/requset/LoginRequest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,9 @@ public class LoginRequest {
66

77
public String password;
88

9+
public LoginRequest(String email, String password) {
10+
this.email = email;
11+
this.password = password;
12+
}
13+
914
}

src/main/java/com/ecommerce/member/dto/requset/ModifyUserRequest.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22

33
public class ModifyUserRequest {
44

5-
public String email;
6-
75
public String userName;
86

97
public String phoneNumber;
8+
9+
public ModifyUserRequest(String userName, String phoneNumber) {
10+
this.userName = userName;
11+
this.phoneNumber = phoneNumber;
12+
}
1013
}

src/main/java/com/ecommerce/member/dto/requset/RegisterRequest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,11 @@ public boolean hasNotPassword() {
1616
return password == null || password.isBlank();
1717
}
1818

19+
public RegisterRequest(String email, String userName, String phoneNumber, String role, String password) {
20+
this.email = email;
21+
this.userName = userName;
22+
this.phoneNumber = phoneNumber;
23+
this.role = role;
24+
this.password = password;
25+
}
1926
}

src/main/java/com/ecommerce/member/memberController/MemberController.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
@RequiredArgsConstructor
2222
public class MemberController {
2323

24+
private final JwtUtil jwtUtil;
2425
private final UserService userService;
2526

2627
@PostMapping("/member/users/registration")
@@ -30,7 +31,7 @@ public UserEntity register(@RequestBody RegisterRequest registerRequest) throws
3031

3132
@PostMapping("/member/users/modify")
3233
public UserEntity modifyUser(@RequestBody ModifyUserRequest dto, @RequestHeader("Authorization") String token) {
33-
String email = JwtUtil.extractEmail(token);
34+
String email = jwtUtil.extractEmail(token);
3435
return userService.modifyUser(email, dto);
3536
}
3637

src/main/java/com/ecommerce/member/memberEntity/UserEntity.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import jakarta.persistence.*;
55

66
@Entity
7+
@Table(name = "users")
78
public class UserEntity {
89

910
@Id
@@ -13,16 +14,25 @@ public class UserEntity {
1314
@Column(unique = true)
1415
public String email;
1516

16-
public String userName;
17-
1817
public String password;
1918

2019
public String salt;
2120

22-
@Column(unique = true)
21+
@Column(name = "user_name")
22+
public String userName;
23+
24+
@Column(name = "phone_number", unique = true)
2325
public String phoneNumber;
2426

27+
public String role;
28+
29+
public UserEntity() {
30+
}
31+
2532
public UserEntity(String email, String userName, String password, String salt, String phoneNumber, String role) {
33+
if(email == null || email.isBlank()) throw new IllegalArgumentException("Email is necessary");
34+
if(password == null || password.isBlank()) throw new IllegalArgumentException("Password is necessary");
35+
2636
this.email = email;
2737
this.userName = userName;
2838
this.password = password;
@@ -31,12 +41,4 @@ public UserEntity(String email, String userName, String password, String salt, S
3141
this.role = role;
3242
}
3343

34-
public String role;
35-
36-
public UserEntity() {
37-
}
38-
39-
40-
41-
4244
}

src/main/java/com/ecommerce/member/memberService/UserService.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
@RequiredArgsConstructor
1818
public class UserService {
1919

20+
private final JwtUtil jwtUtil;
2021
private final UserRepository userRepository;
2122

2223
public UserEntity registerUser(RegisterRequest registerRequest) throws NoSuchAlgorithmException {
@@ -33,7 +34,8 @@ public UserEntity registerUser(RegisterRequest registerRequest) throws NoSuchAlg
3334
}
3435

3536
public UserEntity modifyUser(String email, ModifyUserRequest dto) {
36-
var user = userRepository.findByEmail(email).orElseThrow();
37+
var user = userRepository.findByEmail(email)
38+
.orElseThrow(() -> new IllegalArgumentException("User not found"));
3739

3840
user.userName = dto.userName;
3941
user.phoneNumber = dto.phoneNumber;
@@ -44,7 +46,7 @@ public UserEntity modifyUser(String email, ModifyUserRequest dto) {
4446

4547
public LoginResponse responseToken(LoginRequest loginRequest) throws NoSuchAlgorithmException {
4648
UserEntity loginUser = checkValidPasswd(loginRequest);
47-
String token = JwtUtil.generateToken(loginUser.email);
49+
String token = jwtUtil.generateToken(loginUser.email);
4850

4951
return new LoginResponse(token);
5052
}
@@ -54,14 +56,15 @@ public UserEntity checkValidPasswd(LoginRequest loginRequest) throws NoSuchAlgor
5456
String hashWithSalt = PasswordUtil.hashWithSalt(loginRequest.password, user.salt);
5557

5658
if (!hashWithSalt.equals(user.password)) {
57-
throw new IllegalArgumentException("It has not valid password");
59+
throw new IllegalArgumentException("Not valid password");
5860
}
5961

6062
return user;
6163
}
6264

6365
private UserEntity getUserByEmail(LoginRequest loginRequest) {
64-
return userRepository.findByEmail(loginRequest.email).orElseThrow();
66+
return userRepository.findByEmail(loginRequest.email)
67+
.orElseThrow(() -> new IllegalArgumentException("User not found"));
6568
}
6669

6770

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.ecommerce.util;
2+
3+
import com.google.gson.FieldNamingPolicy;
4+
import com.google.gson.Gson;
5+
import com.google.gson.GsonBuilder;
6+
import com.google.gson.JsonObject;
7+
8+
import java.util.Map;
9+
10+
public interface JsonUtilsDeco {
11+
Gson prettyGson = new GsonBuilder()
12+
.setPrettyPrinting()
13+
.disableHtmlEscaping()
14+
.serializeNulls()
15+
.create();
16+
Gson gson = new GsonBuilder()
17+
.disableHtmlEscaping()
18+
.serializeNulls()
19+
.create();
20+
Gson snakeGson = new GsonBuilder()
21+
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
22+
.disableHtmlEscaping()
23+
.serializeNulls()
24+
.create();
25+
26+
static String convertMapToJsonString(Map<String, String> payload) {
27+
JsonObject obj = new JsonObject();
28+
payload.forEach(obj::addProperty);
29+
return prettyGson.toJson(obj);
30+
}
31+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.ecommerce.util;
2+
3+
import io.jsonwebtoken.security.Keys;
4+
5+
import org.springframework.beans.factory.annotation.Value;
6+
import org.springframework.stereotype.Component;
7+
8+
import javax.crypto.SecretKey;
9+
import java.nio.charset.StandardCharsets;
10+
11+
@Component
12+
public class JwtKeyProvider {
13+
14+
@Value("${jwt.secret}")
15+
private String secret;
16+
17+
public SecretKey getKey() {
18+
return Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
19+
}
20+
}
Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,37 @@
11
package com.ecommerce.util;
22

3+
import io.jsonwebtoken.Claims;
4+
import io.jsonwebtoken.Jws;
5+
import io.jsonwebtoken.Jwts;
6+
import lombok.RequiredArgsConstructor;
7+
import org.springframework.stereotype.Component;
8+
9+
import java.util.Date;
10+
11+
@Component
12+
@RequiredArgsConstructor
313
public class JwtUtil {
414

5-
public static String generateToken(String userId) {
6-
return new String();
15+
private final JwtKeyProvider keyProvider;
16+
17+
public String generateToken(String id) {
18+
19+
return Jwts.builder()
20+
.setSubject(id)
21+
.setIssuedAt(new Date())
22+
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60))
23+
.signWith(keyProvider.getKey(), Jwts.SIG.HS256)
24+
.compact();
25+
26+
}
27+
28+
public String extractEmail(String token) {
29+
Jws<Claims> claimsJws = Jwts.parser().verifyWith(keyProvider.getKey()).build().parseSignedClaims(token);
30+
return replacePrefix(claimsJws.getPayload().getSubject());
731
}
832

9-
public static String extractEmail(String token) {
10-
return new String();
33+
private String replacePrefix(String subject) {
34+
return subject.replace("Bearer ", "");
1135
}
36+
1237
}

src/main/resources/application.yaml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ spring:
44
datasource:
55
driver-class-name: com.mysql.cj.jdbc.Driver
66
url: jdbc:mysql://127.0.0.1:3306/ecommerce
7-
username: root
8-
password: User#1234
7+
username:
8+
password:
99
jpa:
10-
generate-ddl: true
10+
generate-ddl: false
1111
hibernate:
12-
ddl-auto: update
12+
ddl-auto: none
13+
show_sql: true
14+
format_sql: true
15+
1316

1417
logging:
1518
level:
@@ -21,3 +24,7 @@ logging:
2124
sql:
2225
BasicBinder: TRACE
2326

27+
28+
29+
jwt:
30+
secret: ""
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package com.ecommerce.member.memberService;
2+
3+
import com.ecommerce.member.dto.requset.LoginRequest;
4+
import com.ecommerce.member.dto.requset.ModifyUserRequest;
5+
import com.ecommerce.member.dto.requset.RegisterRequest;
6+
import com.ecommerce.member.dto.response.LoginResponse;
7+
import com.ecommerce.member.memberEntity.UserEntity;
8+
import com.ecommerce.member.memberRepository.UserRepository;
9+
import com.ecommerce.util.JsonUtilsDeco;
10+
import org.junit.jupiter.api.DisplayName;
11+
import org.junit.jupiter.api.Test;
12+
import org.springframework.beans.factory.annotation.Autowired;
13+
import org.springframework.boot.test.context.SpringBootTest;
14+
15+
import java.security.NoSuchAlgorithmException;
16+
17+
import static org.assertj.core.api.BDDAssertions.then;
18+
19+
//@SpringBootTest(classes ={
20+
// UserEntity.class
21+
// , UserService.class
22+
// , JwtUtil.class
23+
// , JwtKeyProvider.class
24+
// , PasswordUtil.class})
25+
//@EnableJpaRepositories(basePackages ="com.ecommerce.member.memberRepository")
26+
//@EntityScan(basePackages ="com.ecommerce.member.UserEntity")
27+
//@DataJpaTest
28+
@SpringBootTest
29+
class UserServiceTest {
30+
31+
@Autowired private UserService sut;
32+
@Autowired private UserRepository userRepository;
33+
34+
35+
@Test
36+
@DisplayName("빈이 Null은 아닌지")
37+
void isBeanNotEmpty() {
38+
then(sut).isNotNull();
39+
}
40+
41+
42+
@Test
43+
@DisplayName("회원가입 테스트")
44+
void registerTest() throws NoSuchAlgorithmException {
45+
46+
// Given
47+
RegisterRequest registerRequest = new RegisterRequest("[email protected]", "tempuser", "010-0000-0000", "CUSTOMER", "passwordTest");
48+
49+
// When
50+
UserEntity userEntity = sut.registerUser(registerRequest);
51+
52+
// Then
53+
then(userEntity).isNotNull();
54+
55+
}
56+
57+
58+
@Test
59+
@DisplayName("로그인 요청시 JWT 토큰생성과 응답 테스트")
60+
void responseTokenTest() throws NoSuchAlgorithmException {
61+
62+
// Given
63+
LoginRequest passwordTest = new LoginRequest("[email protected]", "passwordTest");
64+
65+
// When
66+
LoginResponse loginResponse = sut.responseToken(passwordTest);
67+
68+
// Then
69+
then(loginResponse).isNotNull();
70+
71+
JsonUtilsDeco.prettyGson.toJson(loginResponse);
72+
}
73+
74+
@Test
75+
@DisplayName("유저 정보 변경 테스트")
76+
void modifyUserTest() {
77+
String email = "[email protected]";
78+
ModifyUserRequest userRequest = new ModifyUserRequest("tempuser", "010-0000-1234");
79+
sut.modifyUser(email, userRequest);
80+
}
81+
82+
}
83+

0 commit comments

Comments
 (0)