스프링부트, 리액트 http-only jwt 토큰 (with 쿠키) 설정방법

Yunny.Log ·2022년 4월 13일
12

Spring Boot

목록 보기
42/80
post-thumbnail

(+) 제가 직접 제작한 이미지들과 코드들이므로 불펌은 하지 말아주세요! 출처만 남겨주신다면 좋을 것 같습니다! 😊

0) jwt 토큰 소통, 인증, 발급 방식

1) 로그인 시

1-1) 스프링부트의 refresh token 발급

스프링부트는 refresh token을 발급해줄 때 set-cookie 설정을 통해 쿠키를 set 해줘야 합니다.

  • 헤더에 쿠키를 SET하는 코드입니다.
ResponseCookie cookie = ResponseCookie.from("refreshToken", refreshToken)
    .maxAge(7 * 24 * 60 * 60)
    .path("/")
    .secure(true)
    .sameSite("None")
    .httpOnly(true) 
    .build();
response.setHeader("Set-Cookie", cookie.toString()); 
  • refresh token을 발급 받은 아이를 ResponseCookie 인스턴스로 만들어준 후 헤더에 set-cookie를 해줘야 하는 것입니다.
  • 코드에 대한 해석은 아래와 같습니다.
ResponseCookie cookie = ResponseCookie.from("refreshToken", refreshToken)
	// 토큰의 유효 기간
    .maxAge(7 * 24 * 60 * 60)
    .path("/") 
	// https 환경에서만 쿠키가 발동합니다. 
    .secure(true)
	// 동일 사이트과 크로스 사이트에 모두 쿠키 전송이 가능합니다
    .sameSite("None")
    .httpOnly(true) 
    // 브라우저에서 쿠키에 접근할 수 없도록 제한
    .build();
response.setHeader("Set-Cookie", cookie.toString()); 

1-1-1 ) 실제 응답 결과 :
1) json response

    "success": true,
    "code": 0,
    "result": {
        "data": {
            "accessToken": "Bearer eyJhbGciOi~E2MjAyNH0.2PUzUF4ECX3bZFRehI0V27ed_Yu3pd5_dyvdKjqKp3I",
            "refreshToken": "httponly",
            }
	 }

1-2) REFRESH TOKEN은 response header에 SET-COOKIE로 지정되게 된다.

  • set-cookie 옵션으로 클라이언트의 쿠키에 리프레시 토큰을 저장해주는 방식

2) 로그인 후 요청

2-1) 로그인 후 요청 보낼 때 (액세스 토큰이 유효한 경우)

1) 클라이언트 요청 보낼 때 (postman 예시)

  • 클라이언트는 요청을 보낼 때 Authorization 헤더에 Bearer abc... 를 넣는 형식으로 반드시 액세스 토큰을 보내줘야 합니다.

2-2) 로그인 후 요청 보낼 때 (유효하지 않은 경우)

  • 액세스가 유효하지 않다는 에러를 throw 하는 것은 아래와 같은 응답을 돌려준다는 것입니다.

  • 액세스가 유효하지 않다는 응답을 돌려받게 되면, 프론트 단에서는 다시 액세스를 발급받아야 하므로 해야 하므로 액세스 토큰 재발급 요청 api로 이동해서 새로운 액세스를 발급 받아와야 합니다.

  • 이는 아래의 3) 과정을 따라가야 합니다.

3) 액세스 토큰을 리프레시 토큰을 통해 재발급

  • 서버에서 유효한 액세스에 대한 응답 예시는 아래와 같습니다.

  • 서버에서 유효하지 않은 액세스에 대한 응답 예시는 아래와 같습니다.

  • 리프레시 토큰은 쉽게 탈취당하지 않도록 우리가 set 해줄 때 http only 속성으로 쿠키에 저장을 해주었기 때문에, js 브라우저에서나 타인이 쉽게 볼 수 없고 탈취가 어렵습니다.

HTTP Only란?

  • document.cookie와 같은 자바스크립트로 쿠키를 조회하는 것을 막는 옵션입니다.
  • 브라우저에서 HTTP Only가 설정된 쿠키를 조회할 수 없습니다.
  • 서버로 HTTP Request 요청을 보낼때만 쿠키를 전송합니다.
  • 이를 통해 XSS(Cross Site Scripting) 공격을 차단할 수 있습니다.
  • http only 출처
  • 서버는 프론트가 액세스 재발급 해주세요 라는 api를 발동시키게 되면, 쿠키에 저장돼있는 refreshToken을 잡아와서 이 refreshToken이 유효한 지 검사합니다.
    • 유효하다면 액세스를 재발급해줍니다.
      • 액세스 재발급 api는 Authorization에 Bearer 방식으로 리프레쉬 토큰을 담아서 요청을 보내면 서버에서는 리프레쉬토큰 기간 만료 여부, 유효 여부를 따진다.
    • refreshToken기간이 만료됐다면, refreshToken 재발급이 필요하다는 에러를 throw 해야 합니다.
      • 이때 refreshToken이 유효하지 않아서 재발급 해야한다는 말은 사용자를 강제로그아웃 시킨 뒤, 재로그인하도록 만들어야 한다는 것과 똑같습니다.

  • 이때 우리가 쿠키에서 리프레시토큰을 추출해와서 AUTHORIAZATION에 담고 API를 수행하는데, 이때 이 API는 쿠키에서 refreshToken을 아래와 같이 requestHeader로 요구하고, 이렇게 빼온 refreshToken으로 액세스 재발급을 진행해주면 됩니다.


plus : 스프링부트와 REACT CORS 설정 어디에?

  • doFilter 메소드를 호출하는 곳에서 내가 허용할 origin을 명시해줍니다.
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response1 = (HttpServletResponse) response;
        HttpServletRequest request1 = (HttpServletRequest) request;

        response1.setHeader("Access-Control-Allow-Origin", "https://n~y.app");
        response1.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response1.setHeader("Access-Control-Max-Age", "3600");
        response1.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me, Origin,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization");
        response1.setHeader("Access-Control-Allow-Credentials",  "true");

        String token = extractToken(request);

        if(validateToken(token)) {
            // SecurityContext에 Authentication 객체 저장
            setAuthentication(token);
        }

        chain.doFilter(request, response1);
 }

주의사항

  • 응답.setHeader("Access-Control-Allow-Credentials", "true"); 을 설정하는 경우라면
  • 응답.setHeader("Access-Control-Allow-Origin", "cors허용할 사이트"); 에서 cors허용할 사이트를 특정해 지정해줘야 합니다.
  • "*"로 하면 안됩니다.

0개의 댓글