-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
JWT 관련 설정 및 로그인 API 기능 구현
- Loading branch information
Showing
14 changed files
with
294 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
backend/src/main/java/mouda/backend/auth/controller/AuthController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package mouda.backend.auth.controller; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import mouda.backend.auth.dto.LoginRequest; | ||
import mouda.backend.auth.dto.LoginResponse; | ||
import mouda.backend.auth.service.AuthService; | ||
import mouda.backend.common.RestResponse; | ||
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; | ||
|
||
@RestController | ||
@RequestMapping("v1/auth") | ||
@RequiredArgsConstructor | ||
public class AuthController { | ||
|
||
private final AuthService authService; | ||
|
||
@PostMapping("/login") | ||
public ResponseEntity<RestResponse<LoginResponse>> login( | ||
@RequestBody LoginRequest loginRequest) { | ||
LoginResponse response = authService.login(loginRequest); | ||
|
||
return ResponseEntity.ok().body(new RestResponse<>(response)); | ||
} | ||
} |
5 changes: 5 additions & 0 deletions
5
backend/src/main/java/mouda/backend/auth/dto/LoginRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package mouda.backend.auth.dto; | ||
|
||
public record LoginRequest(String nickname) { | ||
|
||
} |
5 changes: 5 additions & 0 deletions
5
backend/src/main/java/mouda/backend/auth/dto/LoginResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package mouda.backend.auth.dto; | ||
|
||
public record LoginResponse(String accessToken) { | ||
|
||
} |
13 changes: 13 additions & 0 deletions
13
backend/src/main/java/mouda/backend/auth/exception/AuthErrorMessage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package mouda.backend.auth.exception; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
|
||
@Getter | ||
@AllArgsConstructor | ||
public enum AuthErrorMessage { | ||
|
||
UNAUTHORIZED("모임이 존재하지 않습니다."); | ||
|
||
private final String message; | ||
} |
11 changes: 11 additions & 0 deletions
11
backend/src/main/java/mouda/backend/auth/exception/AuthException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package mouda.backend.auth.exception; | ||
|
||
import mouda.backend.exception.MoudaException; | ||
import org.springframework.http.HttpStatus; | ||
|
||
public class AuthException extends MoudaException { | ||
|
||
public AuthException(HttpStatus httpStatus, AuthErrorMessage authErrorMessage) { | ||
super(httpStatus, authErrorMessage.getMessage()); | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
backend/src/main/java/mouda/backend/auth/service/AuthService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package mouda.backend.auth.service; | ||
|
||
import mouda.backend.auth.dto.LoginRequest; | ||
import mouda.backend.auth.dto.LoginResponse; | ||
import mouda.backend.member.domain.Member; | ||
import mouda.backend.member.repository.MemberRepository; | ||
import mouda.backend.security.JwtProvider; | ||
import org.springframework.stereotype.Service; | ||
|
||
@Service | ||
public class AuthService { | ||
|
||
private final JwtProvider jwtProvider; | ||
|
||
private final MemberRepository memberRepository; | ||
|
||
|
||
public AuthService(JwtProvider jwtProvider, MemberRepository memberRepository) { | ||
this.jwtProvider = jwtProvider; | ||
this.memberRepository = memberRepository; | ||
} | ||
|
||
public LoginResponse login(LoginRequest loginRequest) { | ||
return memberRepository.findByNickname(loginRequest.nickname()) | ||
.map(member -> { | ||
String token = jwtProvider.createToken(member); | ||
return new LoginResponse(token); | ||
}) | ||
.orElseGet(() -> { | ||
Member newMember = new Member(loginRequest.nickname()); | ||
memberRepository.save(newMember); | ||
String token = jwtProvider.createToken(newMember); | ||
return new LoginResponse(token); | ||
}); | ||
} | ||
} |
9 changes: 5 additions & 4 deletions
9
backend/src/main/java/mouda/backend/member/repository/MemberRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,13 @@ | ||
package mouda.backend.member.repository; | ||
|
||
import java.util.List; | ||
|
||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
import java.util.Optional; | ||
import mouda.backend.member.domain.Member; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface MemberRepository extends JpaRepository<Member, Long> { | ||
|
||
List<Member> findAllByMoimId(long moimId); | ||
List<Member> findAllByMoimId(long moimId); | ||
|
||
Optional<Member> findByNickname(String nickname); | ||
} |
75 changes: 75 additions & 0 deletions
75
backend/src/main/java/mouda/backend/security/JwtProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package mouda.backend.security; | ||
|
||
import io.jsonwebtoken.Claims; | ||
import io.jsonwebtoken.JwtException; | ||
import io.jsonwebtoken.Jwts; | ||
import io.jsonwebtoken.SignatureAlgorithm; | ||
import java.util.Date; | ||
import mouda.backend.auth.exception.AuthErrorMessage; | ||
import mouda.backend.auth.exception.AuthException; | ||
import mouda.backend.member.domain.Member; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.stereotype.Component; | ||
|
||
@Component | ||
public class JwtProvider { | ||
|
||
@Value("${security.jwt.token.secret-key}") | ||
private String secretKey; | ||
|
||
@Value("${security.jwt.token.expire-length}") | ||
private long validityInMilliseconds; | ||
|
||
public JwtProvider( | ||
@Value("${security.jwt.token.secret-key}") String secretKey, | ||
@Value("${security.jwt.token.expire-length}") long validityInMilliseconds | ||
) { | ||
this.secretKey = secretKey; | ||
this.validityInMilliseconds = validityInMilliseconds; | ||
} | ||
|
||
public String createToken(Member member) { | ||
Date now = new Date(); | ||
Date validity = new Date(now.getTime() + validityInMilliseconds); | ||
|
||
return Jwts.builder() | ||
.claim("id", member.getId()) | ||
.claim("nickname", member.getNickname()) | ||
.setIssuedAt(now) | ||
.setExpiration(validity) | ||
.signWith(SignatureAlgorithm.HS256, secretKey) | ||
.compact(); | ||
} | ||
|
||
public long extractMemberId(String token) { | ||
Claims claims = getPayload(token); | ||
return claims.get("id", Long.class); | ||
} | ||
|
||
public String extractNickname(String token) { | ||
Claims claims = getPayload(token); | ||
return claims.get("nickname", String.class); | ||
} | ||
|
||
public Claims getPayload(String token) { | ||
try { | ||
Claims claims = Jwts.parser() | ||
.setSigningKey(secretKey) | ||
.parseClaimsJws(token) | ||
.getBody(); | ||
|
||
validateExpiration(claims); | ||
return claims; | ||
} catch (JwtException | IllegalArgumentException e) { | ||
throw new AuthException(HttpStatus.UNAUTHORIZED, AuthErrorMessage.UNAUTHORIZED); | ||
} | ||
} | ||
|
||
public void validateExpiration(Claims claims) { | ||
if (claims.getExpiration().before(new Date())) { | ||
throw new AuthException(HttpStatus.UNAUTHORIZED, AuthErrorMessage.UNAUTHORIZED); | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
backend/src/test/java/mouda/backend/auth/controller/AuthControllerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package mouda.backend.auth.controller; | ||
|
||
import io.restassured.RestAssured; | ||
import io.restassured.http.ContentType; | ||
import mouda.backend.auth.dto.LoginRequest; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; | ||
|
||
@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT) | ||
public class AuthControllerTest { | ||
|
||
@Autowired | ||
AuthController authController; | ||
|
||
@DisplayName("로그인 하기") | ||
@Test | ||
void login() { | ||
LoginRequest request = new LoginRequest("테바"); | ||
|
||
RestAssured.given().log().all() | ||
.contentType(ContentType.JSON) | ||
.body(request) | ||
.when().post("v1/auth/login") | ||
.then().log().all() | ||
.statusCode(200); | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
backend/src/test/java/mouda/backend/auth/service/AuthServiceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package mouda.backend.auth.service; | ||
|
||
import mouda.backend.auth.dto.LoginRequest; | ||
import mouda.backend.auth.dto.LoginResponse; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
|
||
@SpringBootTest | ||
class AuthServiceTest { | ||
|
||
@Autowired | ||
AuthService authService; | ||
|
||
@DisplayName("로그인을 시도한다.") | ||
@Test | ||
void login() { | ||
LoginRequest request = new LoginRequest("테바"); | ||
|
||
LoginResponse response = authService.login(request); | ||
|
||
System.out.println(response.accessToken()); | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
backend/src/test/java/mouda/backend/security/JwtProviderTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package mouda.backend.security; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
import mouda.backend.config.DatabaseCleaner; | ||
import mouda.backend.member.domain.Member; | ||
import mouda.backend.member.repository.MemberRepository; | ||
import org.junit.jupiter.api.AfterEach; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
|
||
@SpringBootTest | ||
class JwtProviderTest { | ||
|
||
@Autowired | ||
JwtProvider jwtProvider; | ||
|
||
@Autowired | ||
MemberRepository memberRepository; | ||
|
||
@Autowired | ||
private DatabaseCleaner databaseCleaner; | ||
|
||
@AfterEach | ||
void cleanUp() { | ||
databaseCleaner.cleanUp(); | ||
} | ||
|
||
@DisplayName("토큰을 발급한다.") | ||
@Test | ||
void createToken() { | ||
String nickname = "테바"; | ||
Member member = Member.builder() | ||
.nickname(nickname) | ||
.build(); | ||
Member savedMember = memberRepository.save(member); | ||
String token = jwtProvider.createToken(savedMember); | ||
|
||
String savedNickname = jwtProvider.extractNickname(token); | ||
|
||
assertThat(savedNickname).isEqualTo(nickname); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters