Skip to content

Commit

Permalink
#3 feat: 로그아웃 API
Browse files Browse the repository at this point in the history
  • Loading branch information
sojungpp committed Dec 9, 2023
1 parent a7b182a commit cd35104
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 6 deletions.
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ dependencies {
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
implementation 'io.jsonwebtoken:jjwt-impl:0.11.5'
implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5'
// redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ public class Constants {
public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String BEARER_PREFIX = "bearer ";
public static final String CLAIM_NAME = "userId";
public static final String LOGOUT = "LOGOUT";
}
29 changes: 27 additions & 2 deletions src/main/java/com/s1350/sooljangmacha/global/utils/JwtUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,34 @@
import com.s1350.sooljangmacha.global.exception.BaseResponseCode;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Date;
import java.util.concurrent.TimeUnit;

import static com.s1350.sooljangmacha.global.Constants.BEARER_PREFIX;
import static com.s1350.sooljangmacha.global.Constants.CLAIM_NAME;
import static com.s1350.sooljangmacha.global.Constants.*;

@Component
@RequiredArgsConstructor
public class JwtUtil {

@Value("${jwt.secret}")
private String jwtSecret;

private final long accessTokenExpiryTime = 1000L * 60 * 60 * 24 * 14; // 2주
private final RedisTemplate<String, String> redisTemplate;

public static String replaceBearer(String header) {
return header.substring(BEARER_PREFIX.length());
}


public boolean validateToken(String token) {
try {
getBody(token);
Expand Down Expand Up @@ -55,6 +61,7 @@ public Long getJwtContents(String token) {

private Claims getBody(String token) {
try {
if(StringUtils.hasText(redisTemplate.opsForValue().get(token))) throw new BaseException(BaseResponseCode.EXPIRED_TOKEN);
return Jwts.parserBuilder().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody();
} catch (ExpiredJwtException e) {
return e.getClaims();
Expand All @@ -81,4 +88,22 @@ public String issuedToken(String tokenName, long expiryTime, String userId) {
.signWith(getSigningKey())
.compact();
}

public void logout(String token, Long userId) {
setValueOfRedis(token, LOGOUT, getExpiration(token), TimeUnit.MILLISECONDS);
deleteToken(String.valueOf(userId));
}

private void setValueOfRedis(String key, String value, Long expiration, TimeUnit time) {
redisTemplate.opsForValue().set(key, value, expiration, time);
}

private Long getExpiration(String token) {
Date expiration = getBody(token).getExpiration();
return expiration.getTime() - new Date().getTime();
}

private void deleteToken(String userId) {
if (redisTemplate.opsForValue().get(userId) != null) redisTemplate.delete(userId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

@Tag(name = "users", description = "유저 API")
Expand All @@ -29,7 +30,7 @@
public class UserController {
private final UserService userService;

@Operation(summary = "회원가입", description = "회원가입을 한다.")
@Operation(summary = "[박소정] 회원가입", description = "회원가입을 한다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "(S0001)요청에 성공했습니다."),
@ApiResponse(responseCode = "400", description = "(E0001)잘못된 요청입니다. <br> (E0001)닉네임을 입력해 주세요. <br> (E0001)이메일을 입력해 주세요. <br> (E0001)provider를 입력해 주세요. <br> (E0001)올바른 이메일 형식으로 입력해 주세요. <br> (E0001)잘못된 provider 값 입니다. <br> (U0002)이미 가입된 유저입니다.", content = @Content(schema = @Schema(implementation = BaseResponse.class)))
Expand All @@ -39,7 +40,7 @@ public BaseResponse<LoginRes> signup(@RequestBody @Valid SignupReq signupReq) {
return BaseResponse.OK(userService.signup(signupReq));
}

@Operation(summary = "로그인", description = "로그인을 한다.")
@Operation(summary = "[박소정] 로그인", description = "로그인을 한다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "(S0001)요청에 성공했습니다."),
@ApiResponse(responseCode = "400", description = "(E0001)잘못된 요청입니다. <br> (E0001)이메일을 입력해 주세요. <br> (E0001)provider를 입력해 주세요. <br> (E0001)올바른 이메일 형식으로 입력해 주세요. <br> (E0001)잘못된 provider 값 입니다. <br>", content = @Content(schema = @Schema(implementation = BaseResponse.class))),
Expand All @@ -51,8 +52,19 @@ public BaseResponse<LoginRes> login(@RequestBody @Valid LoginReq loginReq) {
}


// @Operation(summary = "로그아웃", description = "")
// @PostMapping("/logout")
@Operation(summary = "[박소정] 로그아웃", description = "로그아웃한다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "(S0001)요청에 성공했습니다."),
@ApiResponse(responseCode = "400", description = "(E0001)잘못된 요청입니다. <br> (E0001)이메일을 입력해 주세요. <br> (E0001)provider를 입력해 주세요. <br> (E0001)올바른 이메일 형식으로 입력해 주세요. <br> (E0001)잘못된 provider 값 입니다. <br>", content = @Content(schema = @Schema(implementation = BaseResponse.class))),
@ApiResponse(responseCode = "404", description = "(U0001)존재하지 않는 유저입니다.", content = @Content(schema = @Schema(implementation = BaseResponse.class))),
})
@PostMapping("/logout")
public BaseResponse logout(@Parameter(hidden = true) @UserAccount User user,
HttpServletRequest request) {
userService.logout(user, request);
return BaseResponse.OK();
}


// @Operation(summary = "회원탈퇴", description = "")
// @PostMapping("/signout")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.s1350.sooljangmacha.user.service;


import com.s1350.sooljangmacha.global.Constants;
import com.s1350.sooljangmacha.global.exception.BaseException;
import com.s1350.sooljangmacha.global.exception.BaseResponseCode;
import com.s1350.sooljangmacha.global.utils.JwtUtil;
Expand All @@ -15,6 +16,8 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;


@Service
@RequiredArgsConstructor
Expand All @@ -39,6 +42,11 @@ public LoginRes signup(SignupReq request) {
}

// 로그아웃
public void logout(User user, HttpServletRequest request) {
String header = request.getHeader(Constants.AUTHORIZATION_HEADER);
String token = jwtUtil.replaceBearer(header);
jwtUtil.logout(token, user.getId());
}

// 회원탈퇴

Expand Down

0 comments on commit cd35104

Please sign in to comment.