티스토리 뷰

자신이 만든 사이트에 등록된(회원가입한) 유저들은

로그인이라는 과정을 거쳐 자신이라는 걸 증명합니다.

 

그리고 로그인한 유저들은 매번 어떠한 특정 페이지에 이동하거나

개인적인 정보가 담긴(프로필) 프라이빗한 페이지 같은 곳에 이동할 때

자기자신이라는 인증과정을 거쳐야 합니다.

이러한 과정을 Authentication이라하며 세션, 토큰 등등 다양한 인증 방식이 있지만

필자는 JWT토큰이라는 방식과 Simple JWT, react-cookie모듈을 통해 인증방식을 구현해 보겠습니다

 

Simple JWT 문서

 

Simple JWT — Simple JWT 5.2.2.post14+g8258b5f documentation

Simple JWT provides a JSON Web Token authentication backend for the Django REST Framework. It aims to cover the most common use cases of JWTs by offering a conservative set of default features. It also aims to be easily extensible in case a desired feature

django-rest-framework-simplejwt.readthedocs.io

 

 

Simple JWT Setting

 

(venv) -> pip install djangorestframework-simplejwt

Simple JWT를 사용하기 위해서 해당 모듈을 설치해 준 뒤

settings.py INSTALLED_APPS, REST_FRAMEWORK부분에 아래 코드를 추가해 줍니다.

#settings.py


INSTALLED_APPS = [
    ...
    'rest_framework_simplejwt',
    ...
]

REST_FRAMEWORK = {
    ...
    'DEFAULT_AUTHENTICATION_CLASSES': (
    'rest_framework_simplejwt.authentication.JWTAuthentication',
    )
    ...
}

그리고 Simple JWT를 통해 발급되는 JWT토큰에 대한 설정을 하기 위해

settings.py에 아래 코드를 추가해 줍니다.

#settings.py

SIMPLE_JWT = {
    "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5),
    "REFRESH_TOKEN_LIFETIME": timedelta(days=1),
    "ROTATE_REFRESH_TOKENS": False,
    "BLACKLIST_AFTER_ROTATION": False,
    "UPDATE_LAST_LOGIN": False,

    "ALGORITHM": "HS256",
    "SIGNING_KEY": SECRET_KEY,
    "VERIFYING_KEY": "",
    "AUDIENCE": None,
    "ISSUER": None,
    "JSON_ENCODER": None,
    "JWK_URL": None,
    "LEEWAY": 0,

    "AUTH_HEADER_TYPES": ("Bearer",),
    "AUTH_HEADER_NAME": "HTTP_AUTHORIZATION",
    "USER_ID_FIELD": "id",
    "USER_ID_CLAIM": "user_id",
    "USER_AUTHENTICATION_RULE": "rest_framework_simplejwt.authentication.default_user_authentication_rule",

    "AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),
    "TOKEN_TYPE_CLAIM": "token_type",
    "TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser",

    "JTI_CLAIM": "jti",

    "SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp",
    "SLIDING_TOKEN_LIFETIME": timedelta(minutes=5),
    "SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1),

    "TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainPairSerializer",
    "TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSerializer",
    "TOKEN_VERIFY_SERIALIZER": "rest_framework_simplejwt.serializers.TokenVerifySerializer",
    "TOKEN_BLACKLIST_SERIALIZER": "rest_framework_simplejwt.serializers.TokenBlacklistSerializer",
    "SLIDING_TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer",
    "SLIDING_TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer",
}

위 코드는 Simple JWT가 발급하게 되는 토큰의 기본설정이 담겨있습니다.

해당 설정을 통해 Access토큰, Refresh토큰의 만료기간이나 JWT토큰이 사용하는 알고리즘 등등

JWT토큰과 관련된 커스터마이징을 진행할 수 있습니다.


위 SIGNING_KEY의 값으로 settings.SECRET_KEY가 담겨있습니다.

SIGINING_KEY는 생성된 토큰의 내용에 서명하는 서명 키이기 때문에

해당 값이 유출되면 나쁜 누군가가 자기 마음대로 토큰을 만들어버릴 수 있어서

사이트의 보안적인 부분이 위험하게 됩니다.

 

그렇기 때문에 해당 SECRET_KEY값을 다른 누군가가 보지 못하도록 숨겨야 합니다.


위 코드들을 다 추가했다면 준비완료입니다.

( SIMPLE_JWT코드는 전부 다 추가할 필요 없이 커스터마이징 할 값만 추가하면 됩니다.)

Simple JWT Setting 문서

 

Settings — Simple JWT 5.2.2.post14+g8258b5f documentation

Some of Simple JWT’s behavior can be customized through settings variables in settings.py: Above, the default values for these settings are shown. ROTATE_REFRESH_TOKENS When set to True, if a refresh token is submitted to the TokenRefreshView, a new refr

django-rest-framework-simplejwt.readthedocs.io

 

 

 

TokenView

Simple JWT는 인증과 관련된 View로직을 제공해 주기 때문에 사용이 매우 간편합니다.

from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)

urlpatterns = [
    ...
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
    ...
]

위 Simple JWT가 제공하는 View중에서 TokenObtainPairView는

사용자가 로그인하기 위해 아이디와 비밀번호에 입력한 데이터를

해당 url에 POST메서드로 body에 전달해서 보내면

아이디와 비밀번호에 맞는 유저가 존재하면 access토큰과 refresh토큰을 응답메시지에 넣어 보내줍니다.

 

그리고 TokenRefreshView는 access토큰이 만료되었을 시

해당 url에 POST메서드로 body에 refresh토큰을 전달해서 보내면

refresh토큰이 access토큰을 재발급해서 응답메시지에 넣어 보내줍니다.

 

실제로 테스트해보면

위 필자가 만든 로그인 사이트에서 아이디와 비밀번호를 입력하고 로그인을 눌렀을 시

이벤트 핸들러인 loadLogin함수가 호출되고

useRef훅을 사용하여 해당 태그에 있는 값을 가져온 뒤 accountLoad함수를 호출합니다.

  const inputIdValue = useRef(null);
  const inputPsValue = useRef(null);

  const loadLogin = (e) => {
    e.preventDefault();
    const id = inputIdValue.current.value;
    const password = inputPsValue.current.value;
    return accountLoad(id, password)
  }

accountLoad 함수는 사용자가 아이디와 비밀번호칸에 입력한 데이터를 인자로 받아

accountAccess를 호출하고 accountAccess비동기 함수는

fetch를 통해 body에 사용자의 아이디와 비밀번호를 담아서

http://localhost:8000/api/token/에 HTTP Request를 보내게 됩니다.

 

그 이후 응답된 데이터를 반환(HTTP Response)하고 해당 반환값을 출력해 보았습니다.

console.log(token)

  const accountLoad = async(user_id, user_pw) => {

    const token = await accountAccess(user_id, user_pw);
    console.log(token);
  }
  
  export default async function accountAccess(id, password) {
  const response = await fetch(`http://localhost:8000/api/token/`, {
    method: "POST",
    headers: {
      "Content-Type" : "application/json"
    },
    body: JSON.stringify({
      "username": id,
      "password": password
    }),
  })
  const token = await response.json();
  return token
}

콘솔을 확인해 보니 사용자의 아이디와 비밀번호가 유효하다면

access토큰과 refresh토큰이 Response 된 걸 확인할 수 있습니다.

만약 사용자가 유효하지 않다면 401 에러와 함께

계정을 찾을 수 없다는 메시지가 도착하게 됩니다.

사용자가 자신의 아이디와 비밀번호를 입력하고

로그인에 성공했다면 access토큰과 refresh토큰을 발급해 주는 부분까지 완료했습니다.

 

하지만 아직 끝이 아닙니다.

해당 토큰을 사용자 브라우저 쿠키에 저장해 줌으로써

로그인에 성공한 유저가 사이트에서 어떠한 요구를 할 때마다(Request를 보낼 때마다)

해당 토큰이 담긴 쿠키를 Request헤더에 동봉함으로써

서버에게 이 사람은 접근해도 되는 권한이 있는 사람입니다를 알려야 합니다.

 

 

 

쿠키

 

응답으로 도착한 토큰 데이터를 저장할 수 있는 곳은 많습니다.

로컬 스토리지에 저장할 수도 있고 쿠키에 저장하거나 세션방식처럼 서버에 해당 토큰을 저장할 수도 있습니다.

 

많은 방식 중에서 필자는 쿠키에 저장하는 방식을 선택했습니다.

가장 일반적인 방식이면서도 편한 방식이고 JWT를 사용하는 본질을 해치지 않는 방식이라고 생각합니다.

 

필자는 react-cookie모듈을 통해 토큰을 브라우저 쿠키에 저장했습니다.

(venv) -> npm install react-cookie

Response로 도착한 각 토큰을 react-cookie의 setCookie를 통해 사용자 브라우저 쿠키에 저장했습니다.

JWT토큰은 자체에 유효기간이 내재되어 있기 때문에

따로 유효기간 설정을 할 필요가 없으며 필자는 개발단계에 있음으로써

setCookie의 세 번째 파라미터인 options부분에 보안적인 요소를 추가하지 않았습니다.

const [cookie, setCookie] = useCookies(['access_token', 'refresh_token']);

const onCookie = (name, token) => {
    setCookie(name, token, {path: '/'});
}

const accountLoad = async(user_id, user_pw) => {

const {access, refresh} = await accountAccess(user_id, user_pw);

onCookie('access_token', access);
onCookie('refresh_token', refresh);
}

만약 httpOnly, secure 등등 보안적인 요소에 대한 설정이 궁금하다면 react-cookie 문서를 확인하시기 바랍니다.

react-cookie 문서

 

react-cookie

Universal cookies for React. Latest version: 4.1.1, last published: 2 years ago. Start using react-cookie in your project by running `npm i react-cookie`. There are 554 other projects in the npm registry using react-cookie.

www.npmjs.com

토큰을 사용자 브라우저의 쿠키에 저장하기 위한 과정을 끝냈으니

이제 다시 테스트해 보겠습니다.

사용자가 유효한 아이디와 비밀번호를 입력 시 로그인에 성공하고

개발자 도구의 Application --> Cookies부분을 보면

refresh_token과 access_token이 저장된 걸 확인할 수 있습니다.

 

이제 사용자는 사이트에 어떠한 Request를 보내든 헤더에 자신이 가지고 있는 쿠키를 전부 동봉해서 보내게 됩니다.

이러한 부분을 잘 이용하여 View로직에서 access토큰이 있는 사람은 특수한 페이지나(Ex. 개인 프로필)

특수한 API에 접근할 수 있도록 할 수 있습니다.

 

참고로 그렇다면 해당 토큰을 통해 이 유저가 통행권은 가지고 있지만 어떠한 유저인지는 어떻게 파악하지?

(해당 유저의 아이디, 메일, 전화번호 같은 유저 데이터 파악)에 대한 의문이 들 수 있습니다.

 

이러한 부분은 JWT Token의 Payload부분을 통해 해결할 수 있습니다.

사용자의 개인적인 데이터 자체를 Payload에 담게 되면 보안상 위험해질 수 있기 때문에

고유한 키를 통해(username 같은) 해당 사용자의 데이터에 접근할 수 있는 API를 제작하면 됩니다.

 

이렇게 Simple JWT & react-cookie 모듈을 사용하여 Authentication기능을 구현해 봤습니다.

Simple JWT와 react-cookie에 대한 더 자세한 내용은 각 문서에서 확인할 수 있습니다.

 

Simple JWT

 

Simple JWT — Simple JWT 5.2.2.post14+g8258b5f documentation

Simple JWT provides a JSON Web Token authentication backend for the Django REST Framework. It aims to cover the most common use cases of JWTs by offering a conservative set of default features. It also aims to be easily extensible in case a desired feature

django-rest-framework-simplejwt.readthedocs.io

react-cookie

 

react-cookie

Universal cookies for React. Latest version: 4.1.1, last published: 2 years ago. Start using react-cookie in your project by running `npm i react-cookie`. There are 554 other projects in the npm registry using react-cookie.

www.npmjs.com

 

댓글
공지사항