Skip to content

Commit

Permalink
Merge pull request #39 from 1223v/auth
Browse files Browse the repository at this point in the history
Fix: Cookie 인증 방식 -> Authorization Header 방식으로 변경
  • Loading branch information
1223v authored Jan 10, 2024
2 parents 2cd2369 + 77f844b commit 83209ef
Show file tree
Hide file tree
Showing 13 changed files with 234 additions and 192 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@
import com.readyvery.readyverydemo.security.customlogin.handler.LoginSuccessHandler;
import com.readyvery.readyverydemo.security.customlogin.service.CustomLoginCeoService;
import com.readyvery.readyverydemo.security.exception.CustomAuthenticationEntryPoint;
import com.readyvery.readyverydemo.security.jwt.config.JwtConfig;
import com.readyvery.readyverydemo.security.jwt.filter.JwtAuthenticationProcessingFilter;
import com.readyvery.readyverydemo.security.jwt.service.JwtService;
import com.readyvery.readyverydemo.security.jwt.service.JwtTokenizer;
import com.readyvery.readyverydemo.security.oauth2.handler.OAuth2LoginFailureHandler;
import com.readyvery.readyverydemo.security.oauth2.handler.OAuth2LoginSuccessHandler;
import com.readyvery.readyverydemo.security.oauth2.service.CustomOAuth2UserService;
Expand All @@ -45,7 +45,7 @@ public class SpringSecurityConfig {
private final JwtService jwtService;
private final CeoRepository ceoRepository;
private final ObjectMapper objectMapper;
private final JwtTokenizer jwtTokenizer;
private final JwtConfig jwtConfig;
private final CustomLoginCeoService customLoginCeoService;
private final OAuth2LoginSuccessHandler oAuth2LoginSuccessHandler;
private final OAuth2LoginFailureHandler oAuth2LoginFailureHandler;
Expand Down Expand Up @@ -119,7 +119,7 @@ public PasswordEncoder passwordEncoder() {

@Bean
public LoginSuccessHandler loginSuccessHandler() {
return new LoginSuccessHandler(jwtService, ceoRepository, jwtTokenizer, objectMapper);
return new LoginSuccessHandler(jwtService, ceoRepository);
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
package com.readyvery.readyverydemo.security.customlogin.handler;

import java.io.IOException;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.readyvery.readyverydemo.domain.repository.CeoRepository;
import com.readyvery.readyverydemo.security.jwt.service.JwtService;
import com.readyvery.readyverydemo.security.jwt.service.JwtTokenizer;
import com.readyvery.readyverydemo.src.ceo.dto.CeoLoginRes;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
Expand All @@ -23,8 +18,6 @@ public class LoginSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

private final JwtService jwtService;
private final CeoRepository ceoRepository;
private final JwtTokenizer jwtTokenizer;
private final ObjectMapper objectMapper;

@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Expand All @@ -41,24 +34,6 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
ceoRepository.saveAndFlush(ceoInfo);
});

// JSON 응답 생성 및 전송

response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpServletResponse.SC_OK);
CeoLoginRes ceoLoginRes = CeoLoginRes.builder()
.success(true)
.message("로그인 성공")
.build();

try {
String jsonResponse = objectMapper.writeValueAsString(ceoLoginRes);
response.getWriter().write(jsonResponse);
} catch (IOException e) {
log.error("응답 작성 중 에러 발생", e);
}
log.info("로그인에 성공하였습니다. 이메일 : {}", email);
log.info("로그인에 성공하였습니다. AccessToken : {}", accessToken);
log.info("발급된 AccessToken 만료 기간 : {}", jwtTokenizer.getAccessTokenExpirationPeriod());
}

private String extractCeoname(Authentication authentication) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public class JwtConfig {
public static final String REFRESH_TOKEN_SUBJECT = "RefreshToken";
public static final String EMAIL_CLAIM = "email";
public static final String USER_NUMBER = "userNumber";
public static final String BEARER = "Bearer ";

@Value("${jwt.secretKey}")
public void setSecretKey(String secretKey) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
// -> RefreshToken이 없거나 유효하지 않다면(DB에 저장된 RefreshToken과 다르다면) null을 반환
// 사용자의 요청 헤더에 RefreshToken이 있는 경우는, AccessToken이 만료되어 요청한 경우밖에 없다.
// 따라서, 위의 경우를 제외하면 추출한 refreshToken은 모두 null
String refreshToken = jwtService.extractRefreshTokenFromCookies(request)
String refreshToken = jwtService.extractRefreshToken(request)
.filter(jwtService::isTokenValid)
.orElse(null);

Expand Down Expand Up @@ -106,7 +106,7 @@ private String reIssueRefreshToken(CeoInfo ceoInfo) {
public void checkAccessTokenAndAuthentication(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {

jwtService.extractAccessTokenFromCookies(request)
jwtService.extractAccessToken(request)
.filter(jwtService::isTokenValid)
.ifPresent(accessToken -> jwtService.extractEmail(accessToken)
.ifPresent(email -> ceoRepository.findByEmail(email)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ public interface JwtService {
/**
* 쿠키에서 RefreshToken 추출
*/
Optional<String> extractRefreshTokenFromCookies(HttpServletRequest request);
Optional<String> extractRefreshToken(HttpServletRequest request);

/**
* 쿠키에서 AccessToken 추출
*/
Optional<String> extractAccessTokenFromCookies(HttpServletRequest request);
Optional<String> extractAccessToken(HttpServletRequest request);

/**
* AccessToken에서 Email 추출
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package com.readyvery.readyverydemo.security.jwt.service;

import java.util.Arrays;
import java.util.NoSuchElementException;
import java.util.Optional;

import org.springframework.stereotype.Service;

import com.auth0.jwt.JWT;
import com.readyvery.readyverydemo.domain.CeoInfo;
import com.readyvery.readyverydemo.domain.repository.CeoRepository;
import com.readyvery.readyverydemo.global.exception.BusinessLogicException;
import com.readyvery.readyverydemo.global.exception.ExceptionCode;
import com.readyvery.readyverydemo.security.jwt.config.JwtConfig;
import com.readyvery.readyverydemo.security.jwt.service.create.JwtTokenGenerator;
import com.readyvery.readyverydemo.security.jwt.service.extract.ExtractToken;
import com.readyvery.readyverydemo.security.jwt.service.sendmanger.JwtTokenizer;

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Getter;
Expand All @@ -25,15 +28,17 @@ public class JwtServiceImpl implements JwtService {

private final CeoRepository ceoRepository;
private final JwtTokenizer jwtTokenizer;
private final JwtTokenGenerator jwtTokenGenerator;
private final JwtConfig jwtConfig;
private final ExtractToken extractToken;

/**
* AccessToken 생성 메소드
*/
@Override
public String createAccessToken(String email) {
CeoInfo ceoInfo = ceoRepository.findByEmail(email)
.orElseThrow(() -> new IllegalArgumentException("이메일에 해당하는 유저가 없습니다."));
return jwtTokenizer.generateAccessToken(email, ceoInfo.getId());
CeoInfo ceoInfo = getCeoInfo(email);
return jwtTokenGenerator.generateAccessToken(email, ceoInfo.getId());
}

/**
Expand All @@ -43,7 +48,7 @@ public String createAccessToken(String email) {
@Override
public String createRefreshToken() {

return jwtTokenizer.generateRefreshToken();
return jwtTokenGenerator.generateRefreshToken();
}

/**
Expand All @@ -52,41 +57,26 @@ public String createRefreshToken() {
@Override
public void sendAccessAndRefreshToken(HttpServletResponse response, String accessToken, String refreshToken) {

response.setStatus(HttpServletResponse.SC_OK);

jwtTokenizer.setAccessTokenCookie(response, accessToken);
jwtTokenizer.setRefreshTokenCookie(response, refreshToken);
jwtTokenizer.addAccessRefreshTokenResponseBody(response, accessToken, refreshToken);
jwtTokenizer.addAccessTokenCookie(response, accessToken);
jwtTokenizer.addRefreshTokenCookie(response, refreshToken);
log.info("Access Token, Refresh Token 헤더 설정 완료");
}

/**
* 쿠키에서 RefreshToken 추출
* RefreshToken 추출
*/
@Override
public Optional<String> extractRefreshTokenFromCookies(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
return Arrays.stream(cookies)
.filter(cookie -> jwtTokenizer.getRefreshCookie().equals(cookie.getName())) // 올바른 필터링 조건
.findFirst()
.map(Cookie::getValue);
}
return Optional.empty();
public Optional<String> extractRefreshToken(HttpServletRequest request) {
return extractToken.extractTokenCookie(request, jwtConfig.getRefreshTokenName());
}

/**
* 쿠키에서 AccessToken 추출
* AccessToken 추출
*/
@Override
public Optional<String> extractAccessTokenFromCookies(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
return Arrays.stream(cookies)
.filter(cookie -> jwtTokenizer.getAccessCookie().equals(cookie.getName())) // 올바른 필터링 조건
.findFirst()
.map(Cookie::getValue);
}
return Optional.empty();
public Optional<String> extractAccessToken(HttpServletRequest request) {
return extractToken.extractTokenHeader(request, jwtConfig.getAccessTokenName());
}

/**
Expand All @@ -113,22 +103,26 @@ public Optional<String> extractEmail(String accessToken) {

@Override
public void updateRefreshToken(String email, String refreshToken) {
CeoInfo ceoInfo = ceoRepository.findByEmail(email)
.orElseThrow(() -> new NoSuchElementException("일치하는 회원이 없습니다."));

CeoInfo ceoInfo = getCeoInfo(email);
ceoInfo.updateRefresh(refreshToken);
ceoRepository.save(ceoInfo);
}

@Override
public boolean isTokenValid(String token) {
try {
JWT.require(jwtTokenizer.getAlgorithm()).build().verify(token);
JWT.require(jwtConfig.getAlgorithm()).build().verify(token);
return true;
} catch (Exception e) {
log.error("유효하지 않은 토큰입니다. {}", e.getMessage());
return false;
}
}

private CeoInfo getCeoInfo(String email) {
return ceoRepository.findByEmail(email).orElseThrow(
() -> new BusinessLogicException(ExceptionCode.USER_NOT_FOUND)
);
}

}

This file was deleted.

Loading

0 comments on commit 83209ef

Please sign in to comment.