110%通过Django&React 2020完成JWT身份验证

ReactJS是一个很棒的前端框架,而Django是一个很棒的后端框架。 但是,像往常一样,在处理琐碎复杂的事情时,很难将两者很好地放在一起。 这不像是在墙上贴香蕉。

这是一个中级教程,超出了大多数使Django和React协同工作的教程范围。 我不仅要在这里给您留下一张不完整的图片。 这就是整个shebang。 克服它并构建有用的东西。 当我们第一次为我的初创公司Lollipop.ai做这件事时,这是一个很大的痛苦,所以请明智地使用此知识并宽恕插件。

为什么还要使用JSON Web令牌? 由于应用程序通常不支持会话,因此我们希望能够构建一个同时支持网络和应用程序的后端API,因此我们将使用JSON Web令牌或JWT来处理会话之间的身份验证切换。前端和后端。 最重要的是,JWT非常紧凑且易于使用。 有关更多信息,请在此处检查Auth0的描述 。

仅需6个步骤即可完成所有操作!

第1部分-Django:
1. Django自定义用户
2. DRF序列化器和身份验证

第2部分-React:
3.作为独立应用程序将React安装在我们的Django项目中
4. 准备React for Authentication ,带有路由,以及注册和登录表单
5. Axios用于请求和令牌
6. 注销和列入黑名单令牌

完整的代码位于GitHub上 ,您可以在各个步骤中浏览分支以查看代码(1-1、1-2),等等。

第1部分:Django后端

1-1)在Django中设置自定义用户

首先,新建目录以容纳我们的整个项目。

$ mkdir django-jwt-react
$ cd django-jwt-react

然后创建我们的虚拟环境并使用pipenv安装。
PS:诗歌更好,但要使第一个虚拟动作开始运行就更加困难

$ pipenv --python 3.7
$ pipenv install django djangorestframework djangorestframework-simplejwt

注意:您可能会在网上看到对名为djangorestframework-jwt的软件包的引用,但不再对其进行维护。 请改用djangorestframework-simplejwt 。

激活虚拟环境并创建Django项目。

$ pipenv shell
$ django-admin startproject djsr

现在,您应该在django-jwt-react/目录中包含以下内容。

-django-jwt-react/
--djsr/
---djsr/ 
----__init__.py
----settings.py
----urls.py 
----wsgi.py
---manage.py
--Pipfile
--Pipfile.lock

在大多数情况下,您将不会在项目中使用Django的常规用户,而是会添加自定义属性,例如喜欢的颜色。 但是当我们在数据库中创建了User模型后,我们修改User模型时,Django并不非常喜欢它。 为了避免这些错误,我们首先创建我们的自定义用户,然后才进行并运行数据库迁移。 Django自己建议这样做。

这是在Django中创建我们的身份验证应用程序的好时机。

$ python djsr/manage.py startapp authentication

并将其添加到settings.pyINSTALLED_APPS中。

# djsr/djsr/settings.py
INSTALLED_APPS = [
    'django.contrib.admin' ,
    'django.contrib.auth' ,
    'django.contrib.contenttypes' ,
    'django.contrib.sessions' ,
    'django.contrib.messages' ,
    'django.contrib.staticfiles' ,
    'authentication'
]

让我们在authentication/models.py创建我们的自定义用户模型,并添加fav_color属性,因为我们确实关心多彩的用户。

# djsr/authentication/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser ( AbstractUser ):
    fav_color  = models.CharField(blank=True, max_length= 120 )

CustomUserAbstractUser扩展,它使我们可以访问标准Django User模型的属性和功能,例如用户名,密码等。 因此,我们不需要将这些添加到我们的。 真好

并使用最基本的ModelAdmin将其添加到authentication / ModelAdmin

# djsr/authentication/admin.py
from django.contrib import admin
from .models import CustomUser
class CustomUserAdmin ( admin . ModelAdmin ):
    model  = CustomUser

admin.site.register(CustomUser, CustomUserAdmin)

最后,在settings.py ,将CustomUser配置为AUTH_USER_MODEL

# djsr/djsr/settings.py
# ...
# Custom user model
AUTH_USER_MODEL = "authentication.CustomUser"

现在,通过我们的自定义用户设置,我们可以进行并运行迁移。 在执行此操作时,还要创建一个超级用户。

$ python djsr/manage.py makemigrations
$ python djsr/manage.py migrate
$ python djsr/manage.py createsuperuser

凉。 现在运行服务器。

$  python djsr/manage.py runserver

您应该看到默认的Django成功页面。

110%通过Django&React 2020完成JWT身份验证_第1张图片

注意:如果在创建CustomUser之前进行了迁移,则可能必须删除并重新创建数据库。

第1–1节的GitHub代码位于此处 。

1–2)DRF串行器和身份验证

太好了,既然您的项目已经设置了“自定义用户”,我们就可以使用该自定义用户和Django Rest Framework + DRF Simple JWT创建基于Java Web令牌的身份验证。 我们已经安装了那些。

本节将涵盖:

一个。 配置DRF + DRF简单JWT
b。 验证并获取刷新和访问令牌
C。 刷新令牌
d。 自定义获取令牌序列化器和视图以添加额外的上下文
e。 注册新用户
F。 创建和测试受保护的视图

1–2a。 配置DRF + DRF简单JWT

为了使球滚动,请在settings.py配置DRF和Simple JWT。 “rest_framework”添加到已安装的应用程序和REST_FRAMEWORK配置字典。 不需要将Django Rest Framework简单JWT包添加到INSTALLED_APPS

# djsr/djsr/settings.py
# Needed for SIMPLE_JWT
from datetime import timedelta
# ...
INSTALLED_APPS = [
    ... 
    'rest_framework' # add rest_framework
]
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES' : (
        'rest_framework.permissions.IsAuthenticated' ,
    ),
    'DEFAULT_AUTHENTICATION_CLASSES' : (
'rest_framework_simplejwt.authentication.JWTAuthentication' ,
    ),  # 
}
SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME' : timedelta(minutes= 5 ),
    'REFRESH_TOKEN_LIFETIME' : timedelta(days= 14 ),
    'ROTATE_REFRESH_TOKENS' : True,
    'BLACKLIST_AFTER_ROTATION' : False,
    'ALGORITHM' : 'HS256' ,
    'SIGNING_KEY' : SECRET_KEY,
    'VERIFYING_KEY' : None,
    'AUTH_HEADER_TYPES' : ( 'JWT' ,),
    'USER_ID_FIELD' : 'id' ,
    'USER_ID_CLAIM' : 'user_id' ,
    'AUTH_TOKEN_CLASSES' : ( 'rest_framework_simplejwt.tokens.AccessToken' ,),
    'TOKEN_TYPE_CLAIM' : 'token_type' ,
}

默认情况下,我们只允许经过身份验证的查看者访问我们的视图,并且他们可以使用来自simplejwt包的JWTAuthentication进行身份验证。

配置简单的JWT可能会有些复杂。 这里要注意的关键是刷新令牌(持续14天)用于获取访问令牌(持续5分钟)。 用户只有使用有效的访问令牌才能访问视图,否则DRF将返回401未经授权的错误。 我们会轮流刷新令牌,以便用户在14天之内访问时无需再次登录,以便于使用。 您可以在旋转令牌后将其列入黑名单,但在此不做介绍。

如果您没有使用库存user_id ,而是使用诸如电子邮件地址之类的东西,那么您还需要更改USER_ID_FIELDUSER_ID_CLAIM以与新的用户ID字段相对应。

请特别注意“ AUTH_HEADER_TYPES ”,因为您稍后在此处放置的任何值都必须反映在React的标头中。 我们将其设置为"JWT" ,但我也看到了“Bearer”用法。

无需再次进行迁移。

1-2b。 验证并获取刷新和访问令牌

我们需要先将DRF简单JWT URL添加到我们的项目中,以便能够测试登录。

# djsr/djsr/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path( 'admin/' , admin.site.urls),
    path( 'api/' , include( 'authentication.urls' ))
]

并在身份验证目录中创建一个新的urls.py ,以便我们可以使用DRF Simple JWT提供的孪生视图来获取令牌对并刷新令牌。

# djsr/authentication/urls.py
from django.urls import path
from rest_framework_simplejwt import views as jwt_views

urlpatterns = [
    path( 'token/obtain/' , jwt_views.TokenObtainPairView.as_view(), name= 'token_create' ),  # override sjwt stock token
    path( 'token/refresh/' , jwt_views.TokenRefreshView.as_view(), name= 'token_refresh' ),
]

现在,将CURL与您先前设置的超级用户凭据一起使用。

$ curl --header "Content-Type: application/json" -X POST http: //127.0.0.1:8000/api/token/obtain/ --data '{"username":"djsr","password":"djsr"}'
{ "refresh" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTU2MTYyMTg0OSwianRpIjoiYmE3OWUxZTEwOWJkNGU3NmI1YWZhNWQ5OTg5MTE0NjgiLCJ1c2VyX2lkIjoxfQ.S7tDJaaymUUNs74Gnt6dX2prIU_E8uqCPzMtd8Le0VI" , "access" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTYwNDEyNTQ5LCJqdGkiOiJiMmM0MjM4MzYyZjI0MTJhYTgyODJjMTMwNWU3ZTQwYiIsInVzZXJfaWQiOjF9.0ry66-v6SUxiewAPNmcpRt99D8B8bu-fgfqOCpVnN1k" }

繁荣。 代币。 我们已通过认证! 可是等等。 有令牌复数。 Refresh令牌持续14天(我们可以认为已登录),但是Access令牌仅持续5分钟。 这意味着,只要您的用户尝试在没有有效访问令牌的情况下访问某些内容,它将被拒绝,然后您需要从前端向后端发送刷新请求以获取新的请求。 让我们用CURL做到这一点。

1–2c。 刷新令牌

从上方获取刷新令牌,然后再次使用CURL:

$ curl --header "Content-Type: application/json" -X POST http: //127.0.0.1:8000/api/token/refresh/ --data '{"refresh":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTU2MTYyMTg0OSwianRpIjoiYmE3OWUxZTEwOWJkNGU3NmI1YWZhNWQ5OTg5MTE0NjgiLCJ1c2VyX2lkIjoxfQ.S7tDJaaymUUNs74Gnt6dX2prIU_E8uqCPzMtd8Le0VI"}'
{ "access" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTYwNDEyOTQ0LCJqdGkiOiI1N2ZiZmI3ZGFhN2Y0MzkwYTZkYTc5NDhhMjdhMzMwMyIsInVzZXJfaWQiOjF9.9p-cXSn2uwwW2E0fX1FcOuIkYPcM85rUJvKBhypy1_c" , "refresh" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTU2MTYyMjI0NCwianRpIjoiYWUyZTNiNmRiNTI0NGUyNDliZjAyZTBiMWI3NTFmZjMiLCJ1c2VyX2lkIjoxfQ.peB-nzZRjzgMjcNASp1TZZ510p3lJt7N9SeCWUt0ngI" }

看看那,新的代币! 如果您在settings.py没有ROTATE_REFRESH_TOKENS:True ,那么Refresh令牌将是相同的,但是由于我们正在轮换使用,因此它也是一个新的Refresh令牌。 只要用户在此过期之前继续访问,就不再需要再次登录。

到底什么构成了JWT? 转至jwt.io并插入您的令牌。对于上面的“刷新令牌”,解码后您将看到。

标头:

{
  "typ" : "JWT" ,
  "alg" : "HS256"
}

有效负载:

{
  "token_type" : "refresh" ,
  "exp" : 1561622244 ,
  "jti" : "ae2e3b6db5244e249bf02e0b1b751ff3" ,
  "user_id" : 1
}

请注意, 令牌!= jti JTI包含在令牌中,以及类型,到期时间和您放入令牌中的任何其他信息。

和访问令牌保存类似的信息。

看看有效载荷如何包含user_id? 您可以使用令牌添加任何想要的信息,您只需要先稍微修改一下声明即可。

1–2d。 自定义获取令牌序列化器和视图

之前,我们在CustomUser模型上添加了fav_color属性。 首先,进入管理面板127.0.0.1:8000/admin/并选择一种颜色。

DRF Simple JWT包使开发自定义声明变得非常容易,因此我们可以通过导入和使用原始序列化器子类化,在每个令牌中发送用户喜欢的颜色。

# djsr/authentication/serializers.py
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer


class MyTokenObtainPairSerializer ( TokenObtainPairSerializer ):

    @ classmethod
    def get_token ( cls , user ):
        token  = super (MyTokenObtainPairSerializer, cls).get_token(user)

        # Add custom claims
        token[ 'fav_color' ] = user.fav_color
        return token

它需要与之相伴的观点。

# djsr/authentication/views.py
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework import permissions
from .serializers import MyTokenObtainPairSerializer
class ObtainTokenPairWithColorView ( TokenObtainPairView ):
    permission_classes  = (permissions.AllowAny,)
    serializer_class = MyTokenObtainPairSerializer

urls.py需要一个新条目来替换打包的条目。

# djsr/authentication/urls.py
from django.urls import path
from rest_framework_simplejwt import views as jwt_views
from .views import ObtainTokenPairWithColorView
urlpatterns = [
    path( 'token/obtain/' , ObtainTokenPairWithColorView.as_view(), name= 'token_create' ),  
    path( 'token/refresh/' , jwt_views.TokenRefreshView.as_view(), name= 'token_refresh' ),
]

旧的Refresh令牌仍然可以获取新的Access令牌,因此,此时您应该将所有未使用的令牌列入黑名单,以有效地注销所有人。

要查看运行中的新令牌,请再次使用CURL。

$ curl --header "Content-Type: application/json" -X POST http: //127.0.0.1:8000/api/token/obtain/ --data '{"username":"djsr","password":"djsr"}'
{ "refresh" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTU2MTYyNjQ5NywianRpIjoiODVhMmRlNWUyNjQ0NGE1ZWFmOGQ1NDAzMmM1ODUxMzIiLCJ1c2VyX2lkIjoxLCJmYXZfY29sb3IiOiIifQ.1eJr6XVZXDm0nmm19tyu9WP9AfdY8Ny_D_tK4Qtvo9E" , "access" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTYwNDE3MTk3LCJqdGkiOiI5ZjE4NmM4OTQ0ZWI0NGYyYmNmYjZiMTQ5MzkyY2Y4YSIsInVzZXJfaWQiOjEsImZhdl9jb2xvciI6IiJ9.Ad2szXkTB4eOqnRk3GIcm1NDuNixZH3rNyf9RIePXCU" }

在那里,您可以在已解码令牌中看到自己的收藏夹颜色。

110%通过Django&React 2020完成JWT身份验证_第2张图片

凉。 为什么这有用? 取决于您的实现,但是最好有一些额外的上下文以及令牌,或者使用自定义序列化器/视图执行自定义操作。 这并不意味着要充当任何类型的get_user_info()函数。 不要那样用。

现在,我们可以登录现有用户并给他们一个令牌。 我们还有两件事要做。 注册用户并创建受保护的视图。

1–2e。 注册用户

令人惊讶的(或没有)创建新用户与JWT毫无关系。 这只是原始的Django Rest Framework。

我们不需要对CustomUser模型做任何事情,但是我们需要为其创建一个序列化器,并将其放入带有URL的视图中。

首先, CustomUserSerializer模型序列化器。 如果您不熟悉Django Rest Framework,则序列化程序主要负责将JSON转换为可用的Python数据结构,然后采取相应措施。 有关串行器的更多信息,请参阅非常好的DRF文档 。 我们使用的这个序列化器是超级典型的。

# djsr/authentication/serializers.py

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework import serializers
from .models import CustomUser
# ...
class CustomUserSerializer(serializers.ModelSerializer):
    "" "
    Currently unused in preference of the below.
    " ""
    email = serializers.EmailField(
        required=True
    )
    username = serializers.CharField()
    password = serializers.CharField(min_length= 8 , write_only=True)

    class Meta :
        model  = CustomUser
        fields = ( 'email' , 'username' , 'password' )
        extra_kwargs = { 'password' : { 'write_only' : True}}

    def create(self, validated_data):
        password = validated_data.pop( 'password' , None)
        instance = self.Meta.model(**validated_data)  # as long as the fields are the same, we can just use this
        if password is not None:
            instance.set_password(password)
        instance.save()
        return instance

对于我们的视图集,而不是使用ModelViewSet ,我们创造我们自己只是一个POST端点观点。 对于CustomUser对象的任何GET请求,我们都有一个不同的终结CustomUser

settings.py由于REST_FRAMEWORK的权限默认值仅是经身份验证的用户只能访问的视图,因此我们必须将权限显式设置为AllowAny ,否则尝试注册并向您付款的新用户将获得未授权的错误。 坏枣

当像我们在此处将数据馈送到模型序列化程序时,只要序列化程序具有create()update()方法,就可以使用serializer.save()神奇地创建(或更新)相应的对象(在我们的案例CustomUser )并返回实例。 文件。

# djsr/authentication/views.py
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework import status, permissions
from rest_framework.response import Response
from rest_framework.views import APIView

from .serializers import MyTokenObtainPairSerializer, CustomUserSerializer

class ObtainTokenPairWithColorView ( TokenObtainPairView ):
    serializer_class  = MyTokenObtainPairSerializer


class CustomUserCreate ( APIView ):
    permission_classes  = (permissions.AllowAny,)

    def post(self, request, format= 'json' ):
        serializer = CustomUserSerializer(data=request.data)
        if serializer.is_valid():
            user = serializer.save()
            if user:
                json = serializer.data
                return Response(json, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

最后,在urls.py我们添加了新视图。

# djsr/authentication/urls.py

from django.urls import path
from rest_framework_simplejwt import views as jwt_views
from .views import ObtainTokenPairWithColorView, CustomUserCreate

urlpatterns = [
    path( 'user/create/' , CustomUserCreate.as_view(), name= "create_user" ),
    path( 'token/obtain/' , ObtainTokenPairWithColorView.as_view(), name= 'token_create' ),
    path( 'token/refresh/' , jwt_views.TokenRefreshView.as_view(), name= 'token_refresh' ),
]

查看+序列化器+ URL =很好。

此时,您将必须确保对其进行测试,因为如果此视图仅限于经过身份验证的用户,则将获得0个新用户。 他们会很不高兴,并且当您有用户时,吸引投资者的几率会上升。 这意味着更多的卷曲。

$ curl --header "Content-Type: application/json" -X POST http: //127.0.0.1:8000/api/user/create/ --data '{"email":"[email protected]","username":"ichiro1","password":"konnichiwa"}'
{ "email" : "[email protected]" , "username" : "ichiro1" }

答对了! 效果很好。

在Django Rest Framework方面,我们的最后一步是创建一个受保护的视图,供我们尝试访问。

1–2f。 创建和测试受保护的视图

我们判断所有这些操作是否奏效的唯一方法是创建一个虚拟视图……我们将其称为HelloWorld……并在尝试使用和不使用Javascript Web令牌身份验证令牌访问它时对其进行保护。

让我们做一个最简单的视图。

# djsr/authentication/views.py

...

class HelloWorldView(APIView):

    def get(self, request):
        return Response(data={ "hello" : "world" }, status=status.HTTP_200_OK)

并将其添加到urls.py

# djsr/authentication/urls.py

from django.urls import path
from rest_framework_simplejwt import views as jwt_views
from .views import ObtainTokenPairWithColorView, CustomUserCreate, HelloWorldView

urlpatterns = [
    path( 'user/create/' , CustomUserCreate.as_view(), name= "create_user" ),
    path( 'token/obtain/' , ObtainTokenPairWithColorView.as_view(), name= 'token_create' ),
    path( 'token/refresh/' , jwt_views.TokenRefreshView.as_view(), name= 'token_refresh' ),
    path( 'hello/' , HelloWorldView.as_view(), name= 'hello_world' )
]

返回CURL。 如果我们正确执行了此操作,则没有令牌的API请求将失败。

$ curl --header "Content-Type: application/json" -X GET http: //127.0.0.1:8000/api/hello/
{ "detail" : "Authentication credentials were not provided." }

如预期的那样。 现在有了凭据。 确保先刷新它们,否则访问令牌已过期。 或尝试使用新用户。

$ curl --header "Content-Type: application/json" -X POST http: //127.0.0.1:8000/api/token/obtain/ --data '{"username":"ichiro1","password":"konnichiwa"}'
{ "refresh" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTU2MTYzODQxNiwianRpIjoiMGM5MjY5NWE0ZGQwNDUyNzk2YTM5NTY3ZDMyNTRkYzgiLCJ1c2VyX2lkIjoyLCJmYXZfY29sb3IiOiIifQ.sV6oNQjQkWw2F3NLMQh5VWWleIxB9OpmIFvI5TNsUjk" , "access" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTYwNDI5MTE2LCJqdGkiOiI1NWVlZDA4MGQ2YTg0MzI4YTZkZTE0Mjg4ZjE3OWE0YyIsInVzZXJfaWQiOjIsImZhdl9jb2xvciI6IiJ9.LXqfhFifGDA6Qg8s4Knl1grPusTLX1lh4YKWuQUuv-k" }
$ curl --header "Content-Type: application/json" -X GET http: //127.0.0.1:8000/api/hello/
{ "detail" : "Authentication credentials were not provided." }
$ curl --header "Content-Type: application/json" --header "Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTYwNDI5MTE2LCJqdGkiOiI1NWVlZDA4MGQ2YTg0MzI4YTZkZTE0Mjg4ZjE3OWE0YyIsInVzZXJfaWQiOjIsImZhdl9jb2xvciI6IiJ9.LXqfhFifGDA6Qg8s4Knl1grPusTLX1lh4YKWuQUuv-k"  -X GET http: //127.0.0.1:8000/api/hello/
{ "hello" : "world" }

首先,我们登录了新用户Ichiro,然后在受保护的端点上尝试了GET请求。 它仍然被拒绝,因为尽管我们可以用肉眼看到它,但实际上并未传递令牌。 它必须在标题中传递。 这就是为什么要记住在settings.py中我们在AUTH_HEADER_TYPES设置“JWT”AUTH_HEADER_TYPES

在标头中,令牌必须以“Authorization: JWT “ + access token 或将AUTH_HEADER_TYPES设置为的任何内容。 否则,没有骰子。 当我们连接前端时,这将变得很重要。

如您所见,当我们这样做时,我们能够获得视图的响应{"hello":"world"}

惊人。 现在,我们可以使用JWT Refresh和Access令牌对自定义用户进行身份验证,并且仅当在标头中传输Access令牌时才允许他们访问受保护的视图。

如果您等待了5分钟并尝试使用过期的访问令牌怎么办?

$ curl -Type: application/json " --header " Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTYwNDI5MTE2LCJqdGkiOiI1NWVlZDA4MGQ2YTg0MzI4YTZkZTE0Mjg4ZjE3OWE0YyIsInVzZXJfaWQiOjIsImZhdl9jb2xvciI6IiJ9.LXqfhFifGDA6Qg8s4Knl1grPusTLX1lh4YKWuQUuv-k "  -X GET http://127.0.0.1:8000/api/hello/
{" detail ":" Given token not valid for any token type "," code ":" token_not_valid "," messages ":[{" token_class ":" AccessToken "," token_type ":" access "," message ":" Token is invalid or expired "}]}

在Django服务器控制台中,您将能够看到魔术:

Unauthorized: /api/ hello/
[ 13 /Jun/ 2019 12 : 53 : 29 ] "GET /api/hello/ HTTP/1.1" 401 183

该视图将无法访问,您必须刷新。 手动使用CURL进行操作非常繁琐,但是在前端框架内,它很容易实现自动化。

接下来,我们将继续使用ReactJS创建前端以使用我们的API。

第1–2节的GitHub代码位于此处 。

第2部分:React Frontend

2–1)将React作为独立应用程序安装在Django项目中

设置前端框架以使用Django可以通过多种方法来完成。 它们可以完全分开,仅通过API进行联系。 在这种情况下,本地开发将运行Django开发服务器和单独的React开发服务器,而部署将涉及独立于后端部署的前端。 例如,当Django托管在EC2服务器上时,对AWS S3做出反应。 这将需要一些有趣的CORS配置。

另一方面,React可以在Django自己的模板系统中更深入地交织在一起,以便Django处理为模板提供服务,但您仍然可以使用React magic。 首先,它有点不利于拥有前端框架的目的。

本教程使用中间方法-将React安装在独立的Django应用程序中。 CORS头文件不需要太多工作,您将获得React框架的全部好处。 有一定的警告。 同一服务器将负责提供所有数据,这可能会减慢数据速度。 如果您想提供一些Django URL,例如运行状况检查或/ admin,URL路由也有些棘手。 初始设置也很麻烦。 我们将逐步解决。

首先要做的是制作一个新的Django应用来保存React。

$ cd djsr
$ python manage.py startapp frontend

并将其添加到settings.pyINSTALLED_APPS中。

在frontend中创建一个templates/frontend/index.html文件,它将作为React以及常规Django渲染索引视图的基础模板。 在此特定模板中,可以使用Django模板上下文处理器,如果要从settings.py控制React的行为,这将非常有用。 现在,让我们像标准Django基本模板一样准备它。




 
{% load static %}

    
    
    
    DRF + React = Winning the game


    
This will be the base template.

并在使用时制作最小的style.css。

// djsr/fontend/static/frontend/style.css

#root{
    background-color:rebeccapurple;
}

我们以视图和更新的URL完成此操作。

# djsr/djsr/urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path( 'admin/' , admin.site.urls),
    path( 'api/' , include( 'authentication.urls' )),
    path( '' , include( 'frontend.urls' ))
]

确保将这个include放在urlpatterns 这样,任何不匹配Django URL的内容都将由前端处理,这使我们可以使用React的路由器来管理前端视图,同时仍将其托管在同一服务器上。 因此很好地避免了CORS的疯狂。

# djsr/frontend/views.py

from django.shortcuts import render

# Create your views here.
def index(request):
    return render(request, 'frontend/index.html' , context=None)

此视图呈现index.html ,它将作为所有React的基础模板。 它需要做的就是渲染模板。 如果需要,可以添加上下文。

最后,我们将此视图添加到前端URL。 我们必须添加两次,首先捕获空URL,例如https://lollipop.ai,然后捕获其他所有URL,例如https://lollipop.ai/lollisignup/ 。

# djsr/frontend/urls.py

urlpatterns = [
    path( '' , index_view),  # for the empty url
    url(r '^.*/$' , index_view)  # for all other urls
]

最后,再次运行服务器,查看索引是否正确显示。

$ cd ../.. (so you 're in project root: django-jwt-react)
$ python djsr/manage.py runserver

导航到http://127.0.0.1/并成功看到此漂亮的几乎为空的页面。 而且您会在http://127.0.0.1:8000/asdjfklasdjfklasdfjklasdf/上看到相同的内容,从而向我们展示了我们并没有弄乱。 至少还没有。 凉。 现在我们可以开始使用React了。

110%通过Django&React 2020完成JWT身份验证_第3张图片

请注意,正则表达式以/ $结尾。 默认情况下,Django在每个URL的末尾添加一个/,因此在React中进行路由时,每个路径的末尾都需要一个/。 这有助于强制执行该纪律。

现在我们可以开始在前端应用程序设置React了。 这不是一项简单的任务,我们不能仅仅依靠Create React App。

相反,我们改编了Jedai Saboteur的精彩教程 ,创建了自己的工具链。

确保您位于应用程序的根文件夹(带有Pipfile)。 首先创建package.json文件。 此处问题的答案无关紧要,因此只需将其保留为默认值即可。

$ npm init

现在,在frontend Django应用程序中,创建一个src目录。 这将保留我们的React组件。 static/frontend目录中,创建另一个名为public的目录,以保存已编译的React文件。

现在,Django应用程序目录应如下所示:

djsr
+-- authentication/
+-- djsr/
+-- frontend/
| +-- migrations/
| +-- src/
| +-- static /
| | +-- frontend/
| | | +-- public/
| | | +-- style.css
| +-- templates/
| | +-- frontend/
| | | +-- index.html
+--db.sqlite3
+--manage.py

打开index.html并将这有点尴尬的行添加到正文的底部。 我们仍然可以在此html文件中使用Django的模板魔术。


                    
                    

你可能感兴趣的:(110%通过Django&React 2020完成JWT身份验证)