diff --git a/pom.xml b/pom.xml
index 1ddbb9c..48d608a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -59,6 +59,25 @@
+
+ io.jsonwebtoken
+ jjwt-api
+ 0.10.7
+
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ 0.10.7
+ runtime
+
+
+
+ io.jsonwebtoken
+ jjwt-orgjson
+ 0.10.7
+ runtime
+
org.flywaydb
flyway-core
diff --git a/src/main/java/com/example/vue/config/SecurityConfiguration.java b/src/main/java/com/example/vue/config/SecurityConfiguration.java
index e821d34..9b884ff 100644
--- a/src/main/java/com/example/vue/config/SecurityConfiguration.java
+++ b/src/main/java/com/example/vue/config/SecurityConfiguration.java
@@ -2,7 +2,9 @@ package com.example.vue.config;
import com.example.vue.config.security.UserDetailsAuthenticationProvider;
import com.example.vue.domain.user.UserDetailsServiceImpl;
+import com.example.vue.util.JwtUtil;
import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
@@ -20,6 +22,9 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@RequiredArgsConstructor
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+ @Value("${jwt.secret}")
+ private String secret;
+
private final UserDetailsServiceImpl userDetailService;
@Override
@@ -50,4 +55,9 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
public AuthenticationProvider authenticationProvider() {
return new UserDetailsAuthenticationProvider(userDetailService, bCryptPasswordEncoder());
}
+
+ @Bean
+ public JwtUtil jwtUtil() {
+ return new JwtUtil(secret);
+ }
}
diff --git a/src/main/java/com/example/vue/domain/auth/AuthController.java b/src/main/java/com/example/vue/domain/auth/AuthController.java
index 581ac39..af59c3c 100644
--- a/src/main/java/com/example/vue/domain/auth/AuthController.java
+++ b/src/main/java/com/example/vue/domain/auth/AuthController.java
@@ -17,8 +17,7 @@ public class AuthController {
@PostMapping(value = "/login")
public LoginResponseDto login(@RequestBody @Valid LoginRequestDto loginRequestDto) {
- authService.login(loginRequestDto);
- return null;
+ return authService.login(loginRequestDto);
}
@PostMapping(value = "/register")
diff --git a/src/main/java/com/example/vue/domain/auth/AuthException.java b/src/main/java/com/example/vue/domain/auth/AuthException.java
index 28e1c36..0872f1c 100644
--- a/src/main/java/com/example/vue/domain/auth/AuthException.java
+++ b/src/main/java/com/example/vue/domain/auth/AuthException.java
@@ -11,4 +11,11 @@ public class AuthException {
super("존재하지 않는 이메일입니다. [email=" + email + "]");
}
}
+
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ public static class PasswordNotMatched extends RuntimeException {
+ public PasswordNotMatched() {
+ super("패스워드가 일치하지 않습니다.");
+ }
+ }
}
diff --git a/src/main/java/com/example/vue/domain/auth/AuthService.java b/src/main/java/com/example/vue/domain/auth/AuthService.java
index db57dfb..be33b36 100644
--- a/src/main/java/com/example/vue/domain/auth/AuthService.java
+++ b/src/main/java/com/example/vue/domain/auth/AuthService.java
@@ -1,19 +1,38 @@
package com.example.vue.domain.auth;
+import com.example.vue.domain.user.User;
import com.example.vue.domain.user.UserRepository;
+import com.example.vue.util.JwtUtil;
import lombok.RequiredArgsConstructor;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
+import java.util.List;
+
@Service
@RequiredArgsConstructor
public class AuthService {
private final UserRepository userRepository;
+ private final BCryptPasswordEncoder bCryptPasswordEncoder;
+ private final JwtUtil jwtUtil;
- public void login(LoginRequestDto loginRequestDto) {
+ public LoginResponseDto login(LoginRequestDto loginRequestDto) {
String email = loginRequestDto.getEmail();
- if (userRepository.findByEmail(email).size() < 1) {
+ String password = loginRequestDto.getPassword();
+
+ List users = userRepository.findByEmail(email);
+ if (users.size() < 1) {
throw new AuthException.NoExistEmail(email);
}
+
+ User user = users.get(0);
+
+ if (!bCryptPasswordEncoder.matches(password, user.getPassword())) {
+ throw new AuthException.PasswordNotMatched();
+ }
+
+ String token = jwtUtil.createToken(user.getId(), user.getName(), "ROLE_USER");
+ return new LoginResponseDto(token);
}
}
diff --git a/src/main/java/com/example/vue/domain/auth/LoginResponseDto.java b/src/main/java/com/example/vue/domain/auth/LoginResponseDto.java
index a00bfd8..fa34694 100644
--- a/src/main/java/com/example/vue/domain/auth/LoginResponseDto.java
+++ b/src/main/java/com/example/vue/domain/auth/LoginResponseDto.java
@@ -5,4 +5,8 @@ import lombok.Data;
@Data
public class LoginResponseDto {
private String token;
+
+ public LoginResponseDto(String token) {
+ this.token = token;
+ }
}
diff --git a/src/main/java/com/example/vue/domain/user/User.java b/src/main/java/com/example/vue/domain/user/User.java
index 2c1477e..04ee8b4 100644
--- a/src/main/java/com/example/vue/domain/user/User.java
+++ b/src/main/java/com/example/vue/domain/user/User.java
@@ -1,5 +1,6 @@
package com.example.vue.domain.user;
+import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
@@ -7,12 +8,16 @@ import javax.persistence.*;
import java.time.LocalDateTime;
@Entity
+@Getter
@NamedQuery(name = "findByEmail", query = "select u from User u where u.email = :email")
public class User {
@Id @GeneratedValue
private Long id;
+ @Column(name = "password")
+ private String password;
+
@Column(name = "email")
private String email;
diff --git a/src/main/java/com/example/vue/util/JwtUtil.java b/src/main/java/com/example/vue/util/JwtUtil.java
new file mode 100644
index 0000000..0d2bbdd
--- /dev/null
+++ b/src/main/java/com/example/vue/util/JwtUtil.java
@@ -0,0 +1,63 @@
+package com.example.vue.util;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.JwtBuilder;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.security.Keys;
+
+import java.security.Key;
+import java.util.Date;
+
+public class JwtUtil {
+
+ private Key key;
+
+ public static long PLUS_MILLS = (1000 * 60 * 60 * 24) * 30L;
+
+ public JwtUtil(String secret) {
+ this.key = Keys.hmacShaKeyFor(secret.getBytes());
+ }
+
+ public String createToken(Long userId, String name, String role) {
+
+ JwtBuilder builder = Jwts.builder()
+ .claim("userId", userId)
+ .claim("name", name)
+ .claim("role", role);
+
+ return builder
+ .signWith(key, SignatureAlgorithm.HS256)
+ .setExpiration(expireTime())
+ .compact();
+
+ }
+
+ private Date expireTime() {
+ Date expireTime = new Date();
+ expireTime.setTime(expireTime.getTime() + PLUS_MILLS);
+ return expireTime;
+ }
+
+ public Claims getClaims(String token) {
+ return Jwts.parser()
+ .setSigningKey(key)
+ .parseClaimsJws(token)
+ .getBody();
+
+ }
+
+ public boolean isUsable(String token) {
+ try {
+ Jwts.parser()
+ .setSigningKey(key)
+ .parseClaimsJws(token)
+ .getBody();
+
+ return true;
+
+ } catch (Exception e) {
+ throw new RuntimeException("권한이 유효하지 않습니다.");
+ }
+ }
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 839fb06..cf35d6d 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -9,4 +9,6 @@ spring.jpa.properties.hibernate.format_sql=true
server.error.include-stacktrace=never
-server.port=7070
\ No newline at end of file
+server.port=7070
+
+jwt.secret=12345678901234567890123456789012
\ No newline at end of file