如何用Django Knox和Postman测试API认证

620 阅读7分钟

用Django Knox和Postman测试API认证

Django-Knox是一个框架,它使用Django Rest框架构建的API端点的认证更容易。然而,Knox也是一种基于令牌的认证,如JSON Web Token(JWT)认证。Django-Knox带有详细的文档,可以轻松实现。

主要收获

在本教程中,将涵盖以下主题。

  1. 为什么Knox要与Django Rest框架一起使用。
  2. 用基于类的视图设计Rest API端点。
  3. 用Django-Knox保证端点的安全。
  4. 用postman应用程序测试API。

现在你已经掌握了什么是Django-Knox,让我们来详细讨论一下它。

为什么使用Django-Knox与DRF

就像我之前说的,Knox解决了DjangoRestFramework中内置TokenAuthentication 的一些问题。如何解决?

  1. 使用Knox,登录视图中的每一次调用都会生成令牌。这使得每个用户都有一个活跃的令牌,当用户注销时就会被删除。
  2. Knox在将令牌存储到数据库之前提供了一个加密的形式。即使数据库被破坏,这一功能也不允许任何黑客访问。
  3. 令牌过期也是Knox的一个关键功能,DRF中没有这个功能。

用基于类的视图设计Rest API

我们正在为一个名为Leads 的应用程序建立Rest API端点。线索将包含线索的所有信息,如姓名、电子邮件、信息和所有者模型。

为了构建API端点,我们必须初始化Django项目。我相信你已经熟悉了Django Rest Framework的项目设置。但如果你不熟悉,请按照下面的命令操作。

$ cd Desktop
$ mkdir myproject
$ cd myproject 
$ virtualenv env
$ cd env
$ source env/Scripts/activate
$ pip install django

最新的Django已经安装完毕。让我们配置项目文件夹,并在你喜欢的代码编辑器中打开它。

$ django-admin startproject Leads
$ cd Leads
$ code  .
$ python manage.py runserver

当你在浏览器中打开端口为8080 的localhost时,Django的默认页面就会自动打开。

为了与Django Rest Framework一起工作,我们必须安装django-rest-framework 这个包。

$ pip install django-rest-framework
$ pip freeze > requirements.txt

requirements.txt 将跟踪所有安装在应用程序中的依赖项。

此外,它还必须附加到框架的其他类中,以便与DRF一起使用Knox。出于这个原因,我们将把下面的python字典添加到settings.py

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ('knox.auth.TokenAuthentication', ),
}

构建Rest API

最好的做法是在项目Leads ,为主导的API做一个单独的应用。要在Django中制作一个应用程序,我们输入命令。

$ python manage.py startapp leadsapi

首先,我们必须在Leads 文件夹的settings.py 中添加每一个产生于INSTALLED_APPS 的应用程序。

INSTALLED_APPS = [
    'rest_framework',
    'knox',
    'leadsapi'
]

此外,我们必须在创建的应用程序的models.py 内定义我们的线索模型。在这个模型中,每个线索将有像nameemailmessage 、最后是owner 的属性。

每条线索都将通过Foreign Key 连接到已建的DjangoUser ,作为所有者。这里是一个实例。

from django.contrib.auth.models import User
from django.db.models.deletion import CASCADE
from datetime import timezone

class LeadModel(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField(max_length=100, unique=True)
    message = models.CharField(max_length=500)
    owner = models.ForeignKey(User, related_name="leads", null=True, on_delete=CASCADE)

    def __str__(self):
        return self.name

现在让我们把模型迁移到数据库中。首先,我们将生成一个迁移文件夹,最后迁移到默认的Sqlite3

$ python manage.py makemigrations
$ python manage.py migrate

我们必须将数据从线索模型中序列化。数据的序列化意味着将模型数据变成JSON 的格式。所以这里是序列化的代码。

from rest_framework import serializers
from leadsapi.models import LeadModel

class LeadSerializer(serializers.ModelSerializer):

    class Meta:
        model = LeadModel
        fields = '__all__'

__all__ 的字段意味着线索的所有属性将被序列化。

在同一个leadsapi 应用程序中,制作一个api.py 。在这里,我们将继承DRF的viewsets ,并映射序列化类。同时,我们将从其他框架中定义permission_class ,并通过名为get_querysets 的方法获得所有线索的查询集。下面的代码做了实现。

from rest_framework import serializers, viewsets, permissions

from leadsapi.models import LeadModel
from .serializers import LeadSerializer

class LeadViewset(viewsets.ModelViewSet):
    serializer_class = LeadSerializer
    permission_classes = [
        permissions.IsAuthenticated
    ]

    def get_queryset(self):
        return self.request.user.leads.all()
    
    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)

到目前为止,所有的事情都很好。接下来的事情是在leadsapi 应用程序中使用urls.py 文件。

在这个文件中,我们将通过注册端点来利用休息框架的路由器。

from rest_framework import routers

from .api import LeadViewset

router = routers.DefaultRouter()
router.register('leads', LeadViewset, 'leads')

urlpatterns = router.urls

每当有HTTP GET/leads 端点的调用时,API会向客户端获取所有的序列化线索。

让我们通过进入Leads文件夹的urls.py ,在项目中注册端点。

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

urlpatterns = [
    path('api/', include('leadsapi.urls')),
    path('', include('accounts.urls'))
]

注意,account.urls 将在本教程的后面使用。

用Django-Knox保证端点的安全

现在我们已经建立了其余的API端点,现在是时候通过只允许认证的用户执行HTTPGETPOST 方法来保护它们。

我们将制作一个新的应用程序,名为account ,我相信我们已经在上面演示过了。按照程序,制作新的应用程序并将其添加到设置中。

正如我们所说,Knox为每个登录的用户提供了一个令牌,以便他们访问安全数据。

我们将利用Django内置的User 模式来序列化用户的数据。这将在新创建的应用程序中的serializers.py 中完成。

from django.contrib.auth import authenticate
from django.contrib.auth.models import User
from django.db import models
from django.db.models import fields
from rest_framework import serializers

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'username', 'email')


class RegisterSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'username', 'email', 'password')
        extra_kwargs = {'password': {'write_only': True}}

    def create(self, validated_data):
        user = User.objects.create_user(validated_data['username'], validated_data['email'], validated_data['password'])
        return user


class LoginSerializer(serializers.Serializer):
    username = serializers.CharField()
    password = serializers.CharField()

    def validate(self, data):
        user = authenticate(**data)
        if user and user.is_active:
            return user
        raise serializers.ValidationError('Incorrect Credentials Passed.')

UserSerializer 类映射了User 模型,并为序列化提取了提到的字段。

RegisterSerialize 类做了同样的事情,但添加了密码字段与write_only 的模式。

LoginSerializer 类做了验证的技巧。validate 方法需要数据作为参数,将其传递给其余框架的authenticate 方法。

我们将用他们的令牌验证用户,令牌已经在传递的数据中。如果提供的令牌匹配,用户将被登录。但如果不是这样,应用程序将发送一个验证错误。

此外,注册和登录的视图应在我们的account 应用程序中名为api.py 的文件中完成。

from django.contrib import auth
from rest_framework import generics, permissions, serializers
from rest_framework.response import Response
from knox.models import AuthToken
from .serializers import UserSerializer, RegisterSerializer, LoginSerializer

class SignUpAPI(generics.GenericAPIView):
    serializer_class = RegisterSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.save()
        token = AuthToken.objects.create(user)
        return Response({
            "users": UserSerializer(user, context=self.get_serializer_context()).data,
            "token": token[1]
        })


class SignInAPI(generics.GenericAPIView):
    serializer_class = LoginSerializer

    def post(self, request):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data
        return Response({
            "user": UserSerializer(user, context=self.get_serializer_context()).data,
            "token": AuthToken.objects.create(user)[1]
        })


class MainUser(generics.RetrieveAPIView):
  permission_classes = [
      permissions.IsAuthenticated
  ]
  serializer_class = UserSerializer

  def get_object(self):
    return self.request.user

下面是对每个类的解释。

至于RegisterAPILoginAPI 类,由于我们使用的是基于类的视图,所以我们将先前制作的序列器提供给serializer_class

每当有用户试图通过发送数据进行注册时,post ,该方法就会被触发,同时生成一个令牌。对于每一个成功注册的用户,将发送一个令牌和用于登录的数据。

UserAPI 将使用户从User 模型中获得。同时,将对收到的用户进行认证。

最后,account 应用程序中的urls.py 文件将被用来为用户的注册和登录制作URL端点。

我们将导入api.py 中的APIViews作为路由的视图。下面是路由的代码。

from django.urls import path, include
from .api import SignUpAPI, SignInAPI, MainUser
from knox import views as knox_views

urlpatterns = [
    path('api/auth/', include('knox.urls')),
    path('api/auth/register', SignUpAPI.as_view()),
    path('api/auth/login', SignInAPI.as_view()),
    path('api/auth/user', MainUser.as_view()),
    path('api/auth/logout',knox_views.LogoutView.as_view(), name="knox-logout"),
]

请注意,我们包括knox.urls 。这是为了路由每个HTTP调用的端点api/auth ,以匹配安全的API。

此外,我们还使用了内置的LogoutView ,以使用户能够注销。

邮递员测试

如果你已经有一个postman,请继续按照下面的程序测试API。

请记住,在你对端点进行HTTP调用之前,服务器必须正在运行。出于这个原因,我们将用下面的命令启动服务器。

$ python manage.py runserver

在我们能够与API互动之前,我们必须先注册,然后登录,我想你应该知道。

  1. http://localhost:8080/api/leadshttp://localhost:8080/api/user 发出一个GET 请求。由于用户没有登录,那么应该发送一个验证错误。

  2. http://localhost:8080/api/auth/register 现在向POST ,并在正文中选择raw "JSON 。为用户提供JSON对象,包括username,email, 和password

响应将是一个令牌,将在登录时用于授权用户。见下面的图片。

Postman Registration API Testing

  1. Headers 复制从注册中发送的令牌,并将其粘贴在Authorization 的值部分,在其前面输入Token ,如下所示。

现在用注册用户的username ,和password ,向http://localhost:8080/api/auth/login 发出一个POST 请求。登录后,将发送另一个新的令牌用于注销。

Postman Log In API Testing

  1. 最后,向领导的API端点提出GET ,你将被允许访问它。这必须在令牌过期前完成。

总结

在本教程中,我们介绍了Django-Knox的实现。我们通过在用户认证和授权的基础上建立其余的API端点,展示了该框架的令牌智能性。