Skip to content

Commit

Permalink
Merge pull request #203 from OutDecision/issue/197
Browse files Browse the repository at this point in the history
[UPDATE]: 로그인 쿠키 수정
  • Loading branch information
baeksom authored May 26, 2024
2 parents 113e90b + d818840 commit 771b0b0
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
Expand All @@ -34,13 +35,14 @@ public ApiResponse<Object> logout(HttpServletResponse response) {
return ApiResponse.onSuccess(null);
}

@PostMapping("/token/refresh")
@GetMapping("/token/refresh")
public ResponseEntity<ApiResponse<Object>> refresh(HttpServletResponse response) {
String accessToken = findMemberService.getTokenFromCookies();
String newAccessToken = tokenService.republishAccessToken(accessToken);
System.out.println("accessToken = " + accessToken);
String newAccessToken = tokenService.republishAccessToken(accessToken, response);
System.out.println("newAccessToken = " + newAccessToken);
if (StringUtils.hasText(newAccessToken)) {
// 클라이언트에게 응답할 때 쿠키를 변경한다.
addCookie(response, "Authorization", newAccessToken, 60*60);
System.out.println("변경 완");
return ResponseEntity.ok(ApiResponse.onSuccess(newAccessToken));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
import KGUcapstone.OutDecision.domain.user.dto.RefreshToken;
import KGUcapstone.OutDecision.domain.user.repository.TokenRepository;
import KGUcapstone.OutDecision.global.common.util.JwtUtil;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

import static KGUcapstone.OutDecision.global.common.util.CookieUtil.addCookie;

@Slf4j
@Service
@RequiredArgsConstructor
Expand Down Expand Up @@ -38,7 +41,7 @@ public void removeRefreshToken(String accessToken) {

// AccessToken 재생성
@Transactional
public String republishAccessToken(String accessToken) {
public String republishAccessToken(String accessToken, HttpServletResponse response) {
// 액세스 토큰으로 Refresh 토큰 객체를 조회
Optional<RefreshToken> refreshToken = tokenRepository.findByAccessToken(accessToken.replace("Bearer ", ""));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public static void addCookie(HttpServletResponse response, String name, String v
.maxAge(maxAge)
.build();

System.out.println("cookie = " + cookie);
response.addHeader("Set-Cookie", cookie.toString());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ public String generateRefreshToken(String email, String role) {


public String generateAccessToken(String email, String role) {
long tokenPeriod = 1000L * 60L * 30L; // 30분

// long tokenPeriod = 1000L * 60L * 30L; // 30분
long tokenPeriod = 1000L * 10L;
Claims claims = Jwts.claims().setSubject(email);
claims.put("role", role);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import KGUcapstone.OutDecision.domain.user.domain.Member;
import KGUcapstone.OutDecision.domain.user.service.FindMemberService;
import KGUcapstone.OutDecision.domain.user.service.auth.TokenService;
import KGUcapstone.OutDecision.global.security.dto.SecurityUserDto;
import KGUcapstone.OutDecision.global.common.util.JwtUtil;
import io.jsonwebtoken.ExpiredJwtException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
Expand All @@ -14,60 +16,72 @@
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.jwt.JwtException;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.List;

import static KGUcapstone.OutDecision.global.common.util.CookieUtil.addCookie;

@RequiredArgsConstructor
@Slf4j
@Component
public class JwtAuthFilter extends OncePerRequestFilter {

private final JwtUtil jwtUtil;
private final FindMemberService findMemberService;
private final TokenService tokenService;

@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException{
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
return request.getRequestURI().contains("/token/");
}

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// request Header에서 AccessToken을 가져온다.
log.info("JwtAuthFilter is called for request URI: {}", request.getRequestURI());
String atc = findMemberService.getTokenFromCookies();

// 토큰 검사 생략(모두 허용 URL의 경우 토큰 검사 통과)
if (!StringUtils.hasText(atc)) {
doFilter(request, response, filterChain);
filterChain.doFilter(request, response);
return;
}

// AccessToken을 검증하고, 만료되었을경우 예외를 발생시킨다.
if (!jwtUtil.verifyToken(atc)) {
throw new JwtException("Access Token 만료!");
boolean isTokenValid = jwtUtil.verifyToken(atc);

if (!isTokenValid) {
log.info("토큰 만료 -> 재발급");
String newAccessToken = tokenService.republishAccessToken(atc, response);

if (newAccessToken != null) {
addCookie(response, "Authorization", newAccessToken, 60 * 60);
atc = newAccessToken;
log.info("토큰 발급 완료 필터 newAccessToken = {}", newAccessToken);
return;
} else {
log.error("새로운 토큰 발급 실패");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "토큰 재발급 실패");
return;
}
}

// AccessToken의 값이 있고, 유효한 경우에 진행한다.
// 아래 코드는 AccessToken이 유효할 때만 실행됨
if (jwtUtil.verifyToken(atc)) {
Member findMember = findMemberService.findByEmail(jwtUtil.getUid(atc)).orElse(null);

// AccessToken 내부의 payload에 있는 email로 user를 조회한다.
Member findMember = findMemberService.findByEmail(jwtUtil.getUid(atc)).get();

// SecurityContext에 등록할 User 객체를 만들어준다.
SecurityUserDto userDto = SecurityUserDto.builder()
.memberId(findMember.getId())
.email(findMember.getEmail())
.role("ROLE_".concat(findMember.getUserRole()))
.nickname(findMember.getNickname())
.build();
if (findMember != null) {
SecurityUserDto userDto = SecurityUserDto.builder()
.memberId(findMember.getId())
.email(findMember.getEmail())
.role("ROLE_".concat(findMember.getUserRole()))
.nickname(findMember.getNickname())
.build();

// SecurityContext에 인증 객체를 등록해준다.
Authentication auth = getAuthentication(userDto);
SecurityContextHolder.getContext().setAuthentication(auth);
Authentication auth = getAuthentication(userDto);
SecurityContextHolder.getContext().setAuthentication(auth);
}
}

filterChain.doFilter(request, response);
Expand All @@ -77,4 +91,4 @@ public Authentication getAuthentication(SecurityUserDto member) {
return new UsernamePasswordAuthenticationToken(member, "",
List.of(new SimpleGrantedAuthority(member.getRole())));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.security.oauth2.jwt.JwtException;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

@Slf4j
@RequiredArgsConstructor
@Component
public class JwtExceptionFilter extends OncePerRequestFilter {
Expand All @@ -22,6 +24,8 @@ public class JwtExceptionFilter extends OncePerRequestFilter {

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
log.info("JwtExceptionFilter is called for request URI: {}", request.getRequestURI());

try {
filterChain.doFilter(request, response);
} catch (JwtException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
log.info("jwtToken = {}", token.getAccessToken());

// 쿠키로 accessToken 전달
addCookie(response, "accessToken", token.getAccessToken(), 60*60);
addCookie(response, "Authorization", token.getAccessToken(), 60*60);

// 로그인 확인 페이지로 리다이렉트 시킨다.
log.info("소셜 로그인 redirect 준비");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
log.info("jwtToken = {}", token.getAccessToken());

// 쿠키로 accessToken 전달
addCookie(response, "Authorization", token.getAccessToken(), 60*60);
addCookie(response, "Authorization", token.getAccessToken(), 60*5);

// 로그인 확인 페이지로 리다이렉트 시킨다.
log.info("일반 로그인 redirect 준비");
Expand Down

0 comments on commit 771b0b0

Please sign in to comment.