Skip to content

Commit

Permalink
test: refresh token test complete(#94)
Browse files Browse the repository at this point in the history
eastmeet committed Jan 26, 2023
1 parent ef4c250 commit e4c422c
Showing 15 changed files with 112 additions and 43 deletions.
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@


import com.main36.pikcha.domain.member.entity.Member;
import io.lettuce.core.Value;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;
18 changes: 14 additions & 4 deletions server/src/main/java/com/main36/pikcha/global/aop/LoginAspect.java
Original file line number Diff line number Diff line change
@@ -2,6 +2,8 @@

import com.main36.pikcha.domain.member.entity.Member;
import com.main36.pikcha.domain.member.service.MemberService;
import com.main36.pikcha.global.exception.BusinessLogicException;
import com.main36.pikcha.global.exception.ExceptionCode;
import com.main36.pikcha.global.security.jwt.JwtParser;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -28,24 +30,32 @@ public class LoginAspect {
private final MemberService memberService;

@Around("@annotation(com.main36.pikcha.global.aop.LoginUserEmail)")
public Object getUserEmail(ProceedingJoinPoint joinPoint) throws Throwable {
public Object getUserEmail(ProceedingJoinPoint joinPoint) {

HttpServletRequest request = ((ServletRequestAttributes) requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
Object[] args = joinPoint.getArgs();
String email = jwtParser.getLoginUserEmail(request);
args[0] = email;

return joinPoint.proceed(args);
try {
return joinPoint.proceed(args);
} catch (Throwable e) {
throw new BusinessLogicException(ExceptionCode.TOKEN_EXPIRED);
}
}

@Around("@annotation(com.main36.pikcha.global.aop.LoginUser)")
public Object getUser(ProceedingJoinPoint joinPoint) throws Throwable {
public Object getUser(ProceedingJoinPoint joinPoint) {
HttpServletRequest request = ((ServletRequestAttributes) requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();

Object[] args = joinPoint.getArgs();
Member loginUser = memberService.getLoginMember(request);
args[0] = loginUser;

return joinPoint.proceed(args);
try {
return joinPoint.proceed(args);
} catch (Throwable e) {
throw new BusinessLogicException(ExceptionCode.TOKEN_EXPIRED);
}
}
}
Original file line number Diff line number Diff line change
@@ -7,7 +7,6 @@ public enum ExceptionCode {
MEMBER_NOT_ALLOW(405, "That Member doesn't have authority"),
MEMBER_EXISTS(409, "Member exists"),
USER_IS_NOT_EQUAL(400, "Client is not equal memberId"),

ATTRACTION_NOT_FOUND(404, "Attraction not found"),
ATTRACTION_EXISTS(409, "Attraction exists"),

@@ -27,9 +26,11 @@ public enum ExceptionCode {
POST_IMAGE_NOT_FOUND(404, "Post Image not found"),

/* JWT */
ACCESS_TOKEN_NOT_FOUND(404,"액세스토큰을 찾을 수 없습니다."),
ACCESS_TOKEN_NOT_FOUND(404,"AccessToken can not be found"),
TOKEN_EXPIRED(400, "Token Expired"),
REFRESH_TOKEN_EXPIRED(400, "RefreshToken Expired"),
TOKEN_INVALID(400, "Token Invalid"),
TOKEN_EMPTY(404, "Token not found"),
TOKEN_SIGNATURE_INVALID(400, "Token Signature Invalid"),
TOKEN_MALFORMED(400, "Token Malformed"),
TOKEN_UNSUPPORTED(400, "Token Unsupported"),
Original file line number Diff line number Diff line change
@@ -64,8 +64,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

.and()
.authorizeHttpRequests(authorize -> authorize
.requestMatchers(toH2Console()).permitAll()
.antMatchers("attractions/upload", "attractions/edit/**", "attractions/delete", "admin").hasRole("ADMIN")
// .requestMatchers(toH2Console()).permitAll()
.antMatchers("/attractions/upload", "/attractions/edit/**", "/attractions/delete", "admin").hasRole("ADMIN")
.anyRequest().permitAll())

.oauth2Login(oauth2 -> oauth2
Original file line number Diff line number Diff line change
@@ -1,35 +1,24 @@
package com.main36.pikcha.global.security.controller;

import com.amazonaws.Response;
import com.main36.pikcha.domain.member.entity.Member;
import com.main36.pikcha.domain.member.service.MemberService;
import com.main36.pikcha.global.aop.LoginUser;
import com.main36.pikcha.global.aop.LoginUserEmail;
import com.main36.pikcha.global.exception.BusinessLogicException;
import com.main36.pikcha.global.exception.ExceptionCode;
import com.main36.pikcha.global.response.DataResponseDto;
import com.main36.pikcha.global.security.dto.RenewTokenDto;
import com.main36.pikcha.global.security.dto.TokenDto;
import com.main36.pikcha.global.security.jwt.JwtGenerator;
import com.main36.pikcha.global.security.jwt.JwtParser;
import com.main36.pikcha.global.security.userdetails.AuthMember;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.util.prefs.PreferenceChangeEvent;

import static com.main36.pikcha.global.security.filter.JwtVerificationFilter.BEARER_PREFIX;

@Slf4j
@RestController
@Validated
@RequiredArgsConstructor
@RequestMapping("/token")

public class TokenController {

private final JwtGenerator jwtGenerator;
@@ -50,11 +39,15 @@ public class TokenController {
// return ResponseEntity.ok(new DataResponseDto<>(renewTokenDto));
// }

@GetMapping("/refresh/{member-id}")
@GetMapping("/token/refresh/{member-id}")
public ResponseEntity<?> findCookie(@PathVariable("member-id") Long memberId,
@CookieValue(value = "refreshToken") String refresh) {
log.info("refresh= {}", refresh);
if (refresh.isEmpty()) {
throw new BusinessLogicException(ExceptionCode.TOKEN_EMPTY);
}

jwtParser.verifyToken(refresh);
jwtParser.verifyRefreshToken(refresh);
Member member = memberService.findMemberByMemberId(memberId);
RenewTokenDto.RenewTokenDtoBuilder builder = RenewTokenDto.builder();
RenewTokenDto renewTokenDto =
@@ -65,4 +58,24 @@ public ResponseEntity<?> findCookie(@PathVariable("member-id") Long memberId,

return ResponseEntity.ok(new DataResponseDto<>(renewTokenDto));
}

// @LoginUser
// @GetMapping("/token/refresh")
// public ResponseEntity<?> findCookie(Member loginUser,
// @CookieValue(value = "refreshToken") String refresh) {
// log.info("refresh= {}", refresh);
// if (refresh.isEmpty()) {
// throw new BusinessLogicException(ExceptionCode.TOKEN_EMPTY);
// }
//
// jwtParser.verifyToken(refresh);
// RenewTokenDto.RenewTokenDtoBuilder builder = RenewTokenDto.builder();
// RenewTokenDto renewTokenDto =
// builder.memberId(loginUser.getMemberId())
// .email(loginUser.getEmail())
// .accessToken("Bearer " + jwtGenerator.generateAccessToken(loginUser.getEmail(), loginUser.getRoles()))
// .build();
//
// return ResponseEntity.ok(new DataResponseDto<>(renewTokenDto));
// }
}
Original file line number Diff line number Diff line change
@@ -15,7 +15,6 @@

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@@ -41,6 +40,7 @@ public class JwtVerificationFilter extends OncePerRequestFilter {
"/home",
"/attractions",
"/posts",
"/token/refresh",
"/oauth2/authorization/google",
"/oauth2/authorization/kakao"
);
@@ -63,7 +63,7 @@ protected void doFilterInternal(HttpServletRequest request,
try {
String jwt = getAccessToken(request);
log.info("jwt = ==== {}", jwt);
if (StringUtils.hasText(jwt) && jwtParser.verifyToken(jwt)) {
if (StringUtils.hasText(jwt) && jwtParser.verifyAccessToken(jwt)) {
Authentication authentication = jwtGenerator.getAuthentication(jwt);
log.info("# Token verification success !");
SecurityContextHolder.getContext().setAuthentication(authentication);
Original file line number Diff line number Diff line change
@@ -64,7 +64,8 @@ public String generateAccessToken(String payload, List<String> roles) {
Claims claims = Jwts.claims().setSubject(payload);
claims.put("roles", roles);
Date now = new Date();
Date validity = new Date(now.getTime() + 30000); // 30000이 30분을 의미함
//TODO: 시간 변경할것
Date validity = new Date(now.getTime() + 30 * 60 * 1000); // 단위 100ns 0.1ms -> 30분

return Jwts.builder()
.setClaims(claims)
@@ -76,7 +77,8 @@ public String generateAccessToken(String payload, List<String> roles) {

public String generateRefreshToken(String payload) {
Date now = new Date();
Date validity = new Date(now.getTime() + 420000); // 420000은 420분을 의미함
//TODO: 시간 변경할것
Date validity = new Date(now.getTime() + 420 * 60 * 1000); // 420분
return Jwts.builder()
.setSubject(payload)
.setIssuedAt(Calendar.getInstance().getTime())
@@ -104,7 +106,7 @@ public TokenDto generateTokenDto(AuthMember authMember) {

// Refresh Token 생성
String refreshToken = Jwts.builder()
.setSubject(authMember.getEmail())
.setSubject(authMember.getMemberId().toString())
.setIssuedAt(Calendar.getInstance().getTime())
.setExpiration(refreshTokenExpiresIn)
.signWith(key, SignatureAlgorithm.HS512)
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.main36.pikcha.global.security.jwt;

import com.main36.pikcha.global.exception.BusinessLogicException;
import com.main36.pikcha.global.exception.ExceptionCode;
import com.main36.pikcha.global.security.jwt.exception.*;
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
@@ -63,13 +65,21 @@ public Date getTokenExpiration(int expirationMinutes) {
}

public String getLoginUserEmail(HttpServletRequest request) {
log.info("token= {}", request.getHeader("Authorization"));
if (request.getHeader("Authorization") == null) {
throw new BusinessLogicException(ExceptionCode.TOKEN_EMPTY);
}

String authorization = request.getHeader("Authorization");
String accessToken = authorization.substring(7);
log.info("authorization= {}", authorization);
// try-catch
String accessToken = authorization.substring(7); // 500 error
verifyAccessToken(accessToken);

return getBody(accessToken).get("sub").toString();
}

public boolean verifyToken(String token) {
public boolean verifyAccessToken(String token) {
try {
getBody(token);
return true;
@@ -91,14 +101,35 @@ public boolean verifyToken(String token) {
}
}

public boolean verifyRefreshToken(String token) {
try {
getBody(token);
return true;
} catch (SignatureException e) {
log.trace("Invalid JWT signature trace: {}", e);
throw new TokenSignatureInvalid();
} catch (MalformedJwtException e) {
log.trace("Invalid JWT token trace: {}", e);
throw new TokenMalformed();
} catch (ExpiredJwtException e) {
log.trace("trace Expired JWT token trace: {}", e);
throw new RefreshExpired();
} catch (UnsupportedJwtException e) {
log.trace("Unsupported JWT token trace: {}", e);
throw new TokenUnsupported();
} catch (IllegalArgumentException e) {
log.trace("JWT claims string is empty trace: {}", e);
throw new TokenEmpty();
}
}

private Claims getBody(String accessToken) {
private Claims getBody(String token) {
// TODO: 예외 처리 필요 키값이 이상할때!
return Jwts.
parserBuilder().
setSigningKey(key)
.build()
.parseClaimsJws(accessToken)
.parseClaimsJws(token)
.getBody();
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.main36.pikcha.global.security.jwt.exception;

import com.main36.pikcha.global.exception.BusinessLogicException;
import com.main36.pikcha.global.exception.ExceptionCode;
import net.minidev.json.writer.BeansMapper;

public class RefreshExpired extends BusinessLogicException {

public RefreshExpired() {
super(ExceptionCode.REFRESH_TOKEN_EXPIRED.getMessage(),ExceptionCode.REFRESH_TOKEN_EXPIRED);
}
}
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
public class TokenExpired extends BusinessLogicException {

public TokenExpired() {
super(ExceptionCode.TOKEN_EXPIRED.getMessage(),ExceptionCode.TOKEN_EXPIRED);
super(ExceptionCode.TOKEN_EXPIRED.getMessage(), ExceptionCode.TOKEN_EXPIRED);
}

}
Original file line number Diff line number Diff line change
@@ -75,12 +75,12 @@ private URI createURI(HttpServletRequest request) {
// queryParams.add("access_token", accessToken);
// queryParams.add("refresh_token", refreshToken);
String serverName = request.getServerName();

log.info("serverName = {}", serverName);
return UriComponentsBuilder
.newInstance()
.scheme("http")
.host(serverName)
// .port()
.port(3000)
// .path("")
// .path("/token/oauth2")
// .queryParams(queryParams)
2 changes: 1 addition & 1 deletion server/src/main/resources/application-local.yml
Original file line number Diff line number Diff line change
@@ -75,7 +75,7 @@ mail:

jwt:
secret-key: ${JWT_SECRET_KEY}
access-token-expiration-minutes: 420
access-token-expiration-minutes: 30
refresh-token-expiration-minutes: 420

cloud:
4 changes: 2 additions & 2 deletions server/src/main/resources/application-server.yml
Original file line number Diff line number Diff line change
@@ -74,8 +74,8 @@ mail:

jwt:
secret-key: ${JWT_SECRET_KEY} # 환경 변수로 설정했음
access-token-expiration-minutes: 1
refresh-token-expiration-minutes: 1
access-token-expiration-minutes: 30
refresh-token-expiration-minutes: 420


cloud:
4 changes: 2 additions & 2 deletions server/src/main/resources/application-test.yml
Original file line number Diff line number Diff line change
@@ -36,7 +36,7 @@ spring:
kakao:
client-id: ${KAKAO_CLIENT_ID}
client-secret: ${KAKAO_CLIENT_SECRET}
redirect-uri: http://localhost:8080/login/oauth2/code/kakao
redirect-uri: http://pikcha36.o-r.kr/login/oauth2/code/kakao
# redirect-uri: http://localhost:8080
authorization-grant-type: authorization_code
client-authentication-method: POST
@@ -71,7 +71,7 @@ mail:

jwt:
secret-key: ${JWT_SECRET_KEY}
access-token-expiration-minutes: 1
access-token-expiration-minutes: 30
refresh-token-expiration-minutes: 420

cloud:
2 changes: 1 addition & 1 deletion server/src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
spring:
profiles:
active: local
active: test

0 comments on commit e4c422c

Please sign in to comment.