인프런 커뮤니티 질문&답변

김영빈님의 프로필 이미지
김영빈

작성한 질문수

파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트

JWT 인증

rest_framework_jwt를 임포트할 수 없다는 에러가 발생합니다

작성

·

1.7K

0

안녕하세요? 강의 잘 듣고 있습니다.
 
강의 11분경 즈음 rest_framework_jwt에러가 발생합니다
가상환경에 알맞게 설치되었는지는 확인했고 / 혹시나 해서 pip uninstall후 다시 install까지 해봣는데도 에러가 발생하네요
찾아보니까 simple-jwt를 써보라는데, 그것도 안되는 것 같았습니다 ㅠ
 
우선 제 settings.py입니다
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
        # 'rest_framework.authentication.TokenAuthentication',
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ],
 
그리고 이렇게 해둔 상태에서 runserver를 cmd에서 돌리니까
다음과 같은 에러가 cmd에서 발생합니다.
 
(askcompany) C:\Users\user\yb\django_askcompany\askcompany\Scripts\_askcompany8>python manage.py runserver Watching for file changes with StatReloader Performing system checks... Exception in thread django-main-thread: Traceback (most recent call last): File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\rest_framework\settings.py", line 177, in import_from_string return import_string(val) File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\django\utils\module_loading.py", line 30, in import_string return cached_import(module_path, class_name) File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\django\utils\module_loading.py", line 15, in cached_import import_module(module_path) File "C:\Users\user\AppData\Local\Programs\Python\Python310\lib\importlib\__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "<frozen importlib._bootstrap>", line 1050, in _gcd_import File "<frozen importlib._bootstrap>", line 1027, in _find_and_load File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 688, in _load_unlocked File "<frozen importlib._bootstrap_external>", line 883, in exec_module File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\rest_framework_jwt\authentication.py", line 4, in <module> from django.utils.encoding import smart_text ImportError: cannot import name 'smart_text' from 'django.utils.encoding' (C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\django\utils\encoding.py) During handling of the above exception, another exception occurred: Traceback (most recent call last): File "C:\Users\user\AppData\Local\Programs\Python\Python310\lib\threading.py", line 1009, in _bootstrap_inner self.run() File "C:\Users\user\AppData\Local\Programs\Python\Python310\lib\threading.py", line 946, in run self._target(*self._args, **self._kwargs) File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\django\utils\autoreload.py", line 64, in wrapper fn(*args, **kwargs) File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\django\core\management\commands\runserver.py", line 124, in inner_run self.check(display_num_errors=True) File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\django\core\management\base.py", line 438, in check all_issues = checks.run_checks( File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\django\core\checks\registry.py", line 77, in run_checks new_errors = check(app_configs=app_configs, databases=databases) File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\django\core\checks\urls.py", line 13, in check_url_config return check_resolver(resolver) File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\django\core\checks\urls.py", line 23, in check_resolver return check_method() File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\django\urls\resolvers.py", line 448, in check for pattern in self.url_patterns: File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\django\utils\functional.py", line 48, in __get__ res = instance.__dict__[self.name] = self.func(instance) File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\django\urls\resolvers.py", line 634, in url_patterns patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module) File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\django\utils\functional.py", line 48, in __get__ res = instance.__dict__[self.name] = self.func(instance) File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\django\urls\resolvers.py", line 627, in urlconf_module return import_module(self.urlconf_name) File "C:\Users\user\AppData\Local\Programs\Python\Python310\lib\importlib\__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "<frozen importlib._bootstrap>", line 1050, in _gcd_import File "<frozen importlib._bootstrap>", line 1027, in _find_and_load File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 688, in _load_unlocked File "<frozen importlib._bootstrap_external>", line 883, in exec_module File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed File "C:\Users\user\yb\django_askcompany\askcompany\Scripts\_askcompany8\_askcompany8\urls.py", line 7, in <module> path('accounts/', include('accounts.urls')), File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\django\urls\conf.py", line 34, in include urlconf_module = import_module(urlconf_module) File "C:\Users\user\AppData\Local\Programs\Python\Python310\lib\importlib\__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "<frozen importlib._bootstrap>", line 1050, in _gcd_import File "<frozen importlib._bootstrap>", line 1027, in _find_and_load File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 688, in _load_unlocked File "<frozen importlib._bootstrap_external>", line 883, in exec_module File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed File "C:\Users\user\yb\django_askcompany\askcompany\Scripts\_askcompany8\accounts\urls.py", line 1, in <module> from rest_framework.authtoken.views import obtain_auth_token File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\rest_framework\authtoken\views.py", line 6, in <module> from rest_framework.schemas import ManualSchema File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\rest_framework\schemas\__init__.py", line 33, in <module> authentication_classes=api_settings.DEFAULT_AUTHENTICATION_CLASSES, File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\rest_framework\settings.py", line 225, in __getattr__ val = perform_import(val, attr) File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\rest_framework\settings.py", line 168, in perform_import return [import_from_string(item, setting_name) for item in val] File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\rest_framework\settings.py", line 168, in <listcomp> return [import_from_string(item, setting_name) for item in val] File "C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\rest_framework\settings.py", line 180, in import_from_string raise ImportError(msg) ImportError: Could not import 'rest_framework_jwt.authentication.JSONWebTokenAuthentication' for API setting 'DEFAULT_AUTHENTICATION_CLASSES'. ImportError: cannot import name 'smart_text' from 'django.utils.encoding' (C:\Users\user\yb\django_askcompany\askcompany\lib\site-packages\django\utils\encoding.py).
 
가상환경에서 사용되는 버전은 다음과 같습니다.
 
늘 빠르고 친절한 답변에 감사드립니다.

답변 5

0

김영빈님의 프로필 이미지
김영빈
질문자

허.. 확인했습니다 ㅠㅠ print문을 넣어도 출력되는 부분이 없었고

cmd에서 python test_token.py를 입력하니까 일단 401을 받았습니다.. 허허.. 진짜 삽질이였네요 ㅠㅠ

감사합니다.. 401을 받은 이유는 한번 더 찾아봐야겠네요.. 혹시 찾게되면 이 댓글을 수정해서 달아놓겠습니다. 

이진석님의 프로필 이미지
이진석
지식공유자

토큰이 만료되었을 경우 401 응답을 받을 수 있습니다.

이 모든 것이 실력향상의 밑거름이 되실 것입니다. 화이팅입니다. :-)

0

김영빈님의 프로필 이미지
김영빈
질문자

개인적으로 일이 있어서 답변을 늦게 확인했네요 우선 답변에 감사드립니다.

해당 강의 15:06초 즈음에 선생님께서 test_token.py를 실행시켜서 , 응답을 받으시는 부분이 있습니다.

simple_jwt를 적용해서 그부분을 동일하게 수행하고, 또 강의에서 처럼 동일한 딕셔너리 형태의 응답을 받기를 기대했는데

이런식으로 수행을 해봐도 아무런 응답이 되돌아 오지 않았습니다.

 

우선 서버는 켜져있는 것을 확인했고, settings.py역시 방금 한번 더 확인했는데, 선생님께서 바로 위에  올려주신 부분과 동일하게 처리되어 있습니다. 혹시몰라 토큰의 유효기간과 관련된 부분도 훨씬 더 긴 시간의 값을 주었습니다.

 

token은 일단 access token과 refresh token을 다음과 같이 받아서 

test_token.py에 복사해서 넣어두었습니다.

현재 제 test_token.py의 내용은 다음과 같습니다

import requests
 
#JWT
JWT_ACCESS_TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjQ4MDk4NzcxLCJpYXQiOjE2NDgwOTUxNzEsImp0aSI6IjMzYTM4ODU1MTI3ZTRhYWJiNzZkNmZhNWI3NTgwZjM1IiwidXNlcl9pZCI6Mn0.Z1mjp40YD6Eg0hQK01-Fp5FzDnk08G0Gfj54F1xtqH8"
JWT_REFRESH_TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTY0ODM1NDM3MSwiaWF0IjoxNjQ4MDk1MTcxLCJqdGkiOiIwN2RjMGY0MDZhMDA0YzRiOWVkNmJlN2Q0MTE2NjJjMSIsInVzZXJfaWQiOjJ9.Qtq40KFnvG994OhlwXFoL8f_nPOUR4_lwKlRmqiJiYs"
 
#JWT헤더
#참고로 bearer : JWT 또는 OAuth토큰을 사용한다는 뜻임
jwt_headers={
    "Authorization": f"Bearer {JWT_ACCESS_TOKEN}"}


res = requests.get("http://localhost:8000/post/1",headers=jwt_headers)

print(res)

강의 마지막부분에서 자꾸 막혀서 자꾸 질문드리는게 죄송하네요 ㅠㅠ 늘 답변주셔서 감사합니다!

 

이진석님의 프로필 이미지
이진석
지식공유자

안녕하세요.

해당 스크립트를 실행하셨을 때, 코드 끝에 print(res) 로 기입하셨는 데, 서버로부터 응답을 받았다면 무엇이라도 출력이 되어야 합니다.

그런데, 아래와 같이 아무 것도 출력이 안 되는 것은 파이썬 스크립트가 실행이 안 된 것은 아닐까요.

코드 시작과 중간 중간에 print("코드 시작점") 과 같이 디버깅 목적으로 print 구문을 넣어서, 해당 내용이 출력되는 지 확인해보세요. 아마도 출력되는 내용이 없지 않을까 싶구요.

파이썬 스크립트를 실행하실 때 test_token.py 명령으로 하셨는 데, 윈도우에서 이는 .py 확장자와 연결된 연결 프로그램이 실행됩니다. 파이썬이 연결되었다면 파이썬이 실행될 수도 있지만, 메모장이 연결되었다면 메모장이 뜰 수도 있습니다.

파이썬에서는 필히 python test_token.py 와 같이 python 인터프리터에게 실행할 파일의 위치를 알려주는 방식으로 실행해주시는 것이 OS 막론하고 보다 명확한 실행방법입니다. 그래야만 내가 원하는 파이썬 인터프리터를 통해 파이썬 코드가 실행됩니다.

화이팅입니다.

0

이진석님의 프로필 이미지
이진석
지식공유자

안녕하세요.

access key를 받으시고 어떤 응답을 기대하셨고, 어떤 응답이 오시나요? 단순히 안된다라고 하시기보다, 예상하시는 결과와 현재의 결과를 설명해주셔야만 보다 좋은 답변을 얻으실 수 있습니다. // 의사도 증상을 알아야 진단을 하는 데, 아프다고만 하면 진단할 수가 없는 것과 같은 이치입니다.

현재의 상황을 파악하시는 연습이 되셔야, 저의 답변이 보다 도움이 되실 것입니다.

저의 경우, djangorestframework-simplejwt 를 설정하고, 아래의 authentication/permission 설정을 하고, 구현된 apiview에서 Authorization 헤더에 Bearer와 함께 jwt access token을 설정하고 요청하여 200 응답을 받았습니다.

장고에는 수많은 라이브러리가 있지만, 단순히 복&붙만으로 동작만을 확인하고 넘어가면 나중에 이슈가 생겼을때 대응하기 힘듭니다. 수많은 라이브러리를 통해 우리가 개발을 보다 수월하게 할 수 있지만, 이는 우리가 개발할 공수를 줄여주는 것일 뿐, 그 라이브러리를 잘 파악할 필요는 있습니다. // 내공을 쌓아가는 거죠.

차근차근 파악해보세요.

화이팅입니다. :-)

0

김영빈님의 프로필 이미지
김영빈
질문자

감사합니다 선생님~ 말씀대로 simple_jwt를 적용시켜보았는데요

설정을 하고 토큰을 잘받고, cpython에 진입해서 token을 뜯어보는 것 까지는 다 잘 실행이 되엇는데요

강의중에 test_token.py를 만들고 requests.get을 활용해서 응답을 받는 부분이 안되더라구요

import requests
JWT_ACCESS_TOKEN = "ey..."

#header
jwt_headers={
    "Authorization": f"Bearer {JWT_ACCESS_TOKEN}"}
   
res = requests.get("http://localhost:8000/post/1",headers = jwt_headers)
print(res)

이렇게 저렇게 찾아보다가 header의 authorization에 bearer를 넣어서(이 bearer가 jwt타입의 토큰을 사용한다는 뜻이더군요!) 하면 다른 분들의 코드에서는 잘 작동하는 것 같은데, 저는 응답이 돌아오지를 않네요.. 토큰의 유효기간 문제는 아닌 듯 합니다. 

혹시 괜찮으시면 키워드를 던져주실 수 있으실까요? 어떤 부분을 찾아봐야할지를 잘 모르겠네요 ㅠㅠ

 

 

0

이진석님의 프로필 이미지
이진석
지식공유자

안녕하세요.

강의에서 소개해드린 django-rest-framework-jwt 라이브러리는 장고 3.x 버전까지 지원합니다. django-rest-framework-jwt 라이브러리 내에 사용된 django api가 장고 버전4부터 없어져서 발생하는 import error 입니다.

관련 코드 : https://github.com/jpadilla/django-rest-framework-jwt/blob/master/rest_framework_jwt/authentication.py#L4

위 링크의 from django.utils.encoding import smart_text API는 장고 버전3까지 유효하며, 장고 4부터는 from django.utils.encoding import force_str 로 사용하여야 하거든요.

현재 장고 버전 4를 설치하셨는 데 강의에서는 장고 버전 3를 설치해서 진행을 하였습니다. 그래서 강의대로 django-rest-framework-jwt 라이브러리를 진행하실 경우, 장고 버전 3로 학습해주시길 권장드립니다. 학습 이후에 라이브러리 버전을 올려주세요.

 

django-rest-framework-jwt 라이브러리는 현재는 더 이상 유지보수가 되지 않고, django-restframework-jwt 개발자는 대안으로 drf-jwt 라이브러리djangorestframework-simplejwt 라이브러리를 제시하고 있습니다.

관련 이슈 : https://github.com/jpadilla/django-rest-framework-jwt/issues/484

학습 이후에 drf-jwt 라이브러리djangorestframework-simplejwt 라이브러리를 적용해보실 수 있겠는 데요.

  • drf-jwt 라이브러리는 django-rest-framework-jwt 라이브러리의 Fork 버전이므로, 장고4로 올리셔도 강의에서 언급한 설정을 그대로 가져가실 수 있구요.
  • djangorestframework-simplejwt 라이브러리는 다른 라이브러리이므로 설정이 다릅니다. 하지만 설정이 크게 다르지 않기에 공식문서를 보시고 적용해보시기에 무리가 없으실 것입니다. 하지만 세부 설정은 조금 다르기에 매뉴얼을 차근차근 살펴보셔야 합니다.

 

화이팅입니다. :-)

김영빈님의 프로필 이미지
김영빈

작성한 질문수

질문하기