Skip to content

Commit

Permalink
feat: JJWT 버전 업그레이드
Browse files Browse the repository at this point in the history
  • Loading branch information
mgstyle97 committed Jan 16, 2024
1 parent 62accda commit 67066a2
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 59 deletions.
8 changes: 7 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ repositories {
mavenCentral()
}

ext {
jwt_version = "0.12.3"
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'com.h2database:h2'
Expand All @@ -37,7 +41,9 @@ dependencies {

implementation 'org.mindrot:jbcrypt:0.4'

implementation 'io.jsonwebtoken:jjwt:0.9.1'
implementation "io.jsonwebtoken:jjwt-api:${jwt_version}"
runtimeOnly "io.jsonwebtoken:jjwt-gson:${jwt_version}"
runtimeOnly "io.jsonwebtoken:jjwt-impl:${jwt_version}"
implementation 'javax.xml.bind:jaxb-api:2.3.1'

// actuator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,70 @@

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import io.wisoft.wasabi.domain.member.persistence.Role;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;

@Component
public class JwtTokenProvider {

@Value("${jwt.token.secret-key}")
private String secretKey;
private final String secretKey;

@Value("${jwt.access-token.expire-length}")
private long accessTokenValidityInMilliseconds;
private final long accessTokenValidityInMilliseconds;

@Value("${jwt.issuer}")
private String issuer;
private final String issuer;

private final SecretKey key;

public JwtTokenProvider(@Value("${jwt.token.secret-key}") final String secretKey,
@Value("${jwt.access-token.expire-length}") final long accessTokenValidityInMilliseconds,
@Value("${jwt.issuer}") final String issuer) {
this.secretKey = secretKey;
this.accessTokenValidityInMilliseconds = accessTokenValidityInMilliseconds;
this.issuer = issuer;
this.key = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
}

public String createAccessToken(final Long memberId, final String name, final Role role, final boolean activation) {
final Date now = new Date();
final Date validity = new Date(now.getTime() + this.accessTokenValidityInMilliseconds);

return Jwts.builder()
.setIssuer(this.issuer)
.setSubject(this.issuer + "/members/" + memberId)
.claim("memberId", memberId)
.claim("memberName", name)
.claim("memberRole", role)
.claim("memberActivation", activation)
.setIssuedAt(now)
.setExpiration(validity)
.signWith(SignatureAlgorithm.HS256, secretKey.getBytes())
.compact();
.issuer(this.issuer)
.subject(this.issuer + "/members/" + memberId)
.claim("memberId", memberId)
.claim("memberName", name)
.claim("memberRole", role)
.claim("memberActivation", activation)
.issuedAt(now)
.expiration(validity)
.signWith(this.key)
.compact();
}

public Long decodeAccessToken(final String accessToken) {

return Jwts.parser()
.setSigningKey(secretKey.getBytes())
.parseClaimsJws(accessToken)
.getBody()
.get("memberId", Long.class);
.verifyWith(this.key)
.build()
.parseSignedClaims(accessToken)
.getPayload()
.get("memberId", Double.class)
.longValue();
}

public Role decodeRole(final String accessToken) {
final Claims claims = Jwts.parser()
.setSigningKey(secretKey.getBytes())
.parseClaimsJws(accessToken)
.getBody();
final Claims claims = Jwts.parser()
.verifyWith(this.key)
.build()
.parseSignedClaims(accessToken)
.getPayload();

return Role.valueOf(claims.get("memberRole", String.class));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@
import io.wisoft.wasabi.domain.auth.exception.LoginFailException;
import io.wisoft.wasabi.domain.auth.web.dto.LoginRequest;
import io.wisoft.wasabi.domain.auth.web.dto.SignupRequest;
import io.wisoft.wasabi.domain.member.application.MemberMapper;
import io.wisoft.wasabi.domain.member.application.MemberRepository;
import io.wisoft.wasabi.domain.member.exception.EmailOverlapException;
import io.wisoft.wasabi.domain.member.persistence.Member;
import io.wisoft.wasabi.domain.member.persistence.Role;
import io.wisoft.wasabi.global.config.common.bcrypt.BcryptEncoder;
import io.wisoft.wasabi.global.config.common.jwt.JwtTokenProvider;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.extension.ExtendWith;
Expand Down Expand Up @@ -39,6 +38,13 @@ class AuthServiceTest {
@Mock
private JwtTokenProvider jwtTokenProvider;

@BeforeAll
static void setup() {
//
new BcryptEncoder("$2a$10$wisoftwasabiprojectsaltkey02023");
// new BcryptEncoder("$2a$10$wisoftwasabiprojectsaltkey02023");
}

@Nested
@DisplayName("회원 가입")
class SignUp {
Expand All @@ -50,34 +56,13 @@ void signUp_success(final SignupRequest request) {

//given

final var mockMember = new Member(
request.email(),
BcryptEncoder.encrypt(request.password()),
request.name(),
request.phoneNumber(),
false,
Role.GENERAL,
request.referenceUrl(),
request.part(),
request.organization(),
request.motto()
);
final var member = MemberMapper.signUpRequestToEntity(request);
given(memberRepository.existsByEmail(request.email())).willReturn(false);

// TODO
////<<<<<<< HEAD:src/test/java/io/wisoft/wasabi/domain/auth/application/AuthServiceTest.java
// final var mockResponse = new SignupResponse(1L);
//
// given(memberMapper.entityToMemberSignupResponse(any())).willReturn(mockResponse);
//
////=======
////>>>>>>> develop:src/test/java/io/wisoft/wasabi/domain/auth/AuthServiceTest.java
//when
final var response = authService.signup(request);

//then
assertThat(response.id()).isNotNull();
assertThat(response).isNotNull();
}


Expand All @@ -100,18 +85,29 @@ void signUp_fail_duplicate_email(final SignupRequest request) {
@DisplayName("로그인")
class Login {

// [java.lang.IllegalArgumentException: Invalid salt version] 발생 - 추후 처리
// @ParameterizedTest
// @AutoSource
@ParameterizedTest
@AutoSource
@DisplayName("이메일, 비밀번호가 일치하여 로그인에 성공한다.")
void login_success(final Member member) {

//given
final var ACCESS_TOKEN = "accessToken";
final var request = new LoginRequest(member.getEmail(), member.getPassword());
final var mockMember = new Member(
member.getEmail(),
BcryptEncoder.encrypt(member.getPassword()),
member.getName(),
member.getPhoneNumber(),
false,
member.getRole(),
member.getReferenceUrl(),
member.getPart(),
member.getOrganization(),
member.getMotto()
);
final var request = new LoginRequest(mockMember.getEmail(), member.getPassword());

given(memberRepository.findMemberByEmail(request.email())).willReturn(Optional.of(member));
given(jwtTokenProvider.createAccessToken(eq(member.getId()), eq(member.getName()), eq(member.getRole()), anyBoolean())).willReturn(ACCESS_TOKEN);
given(memberRepository.findMemberByEmail(request.email())).willReturn(Optional.of(mockMember));
given(jwtTokenProvider.createAccessToken(eq(mockMember.getId()), eq(mockMember.getName()), eq(mockMember.getRole()), anyBoolean())).willReturn(ACCESS_TOKEN);

//when
final var response = authService.login(request);
Expand All @@ -134,9 +130,8 @@ void login_fail_not_exist_email(final LoginRequest request) {
assertThrows(LoginFailException.class, () -> authService.login(request));
}

// [java.lang.IllegalArgumentException: Invalid salt version] 발생 - 추후 처리
// @ParameterizedTest
// @AutoSource
@ParameterizedTest
@AutoSource
@DisplayName("이메일은 존재하지만, 비밀번호가 존재하지 않아 로그인에 실패한다.")
void login_fail_invalid_password(final Member member) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ void read_my_boards(
void read_my_like_boards(final Member member, final Board board1, final Board board2) throws Exception {

// given
memberRepository.save(member);

new Like(member, board1);
new Like(member, board2);

Expand Down

0 comments on commit 67066a2

Please sign in to comment.