用Django Knox和Postman测试API认证
Django-Knox是一个框架,它使用Django Rest框架构建的API端点的认证更容易。然而,Knox也是一种基于令牌的认证,如JSON Web Token(JWT)认证。Django-Knox带有详细的文档,可以轻松实现。
主要收获
在本教程中,将涵盖以下主题。
- 为什么Knox要与Django Rest框架一起使用。
- 用基于类的视图设计Rest API端点。
- 用Django-Knox保证端点的安全。
- 用postman应用程序测试API。
现在你已经掌握了什么是Django-Knox,让我们来详细讨论一下它。
为什么使用Django-Knox与DRF
就像我之前说的,Knox解决了DjangoRestFramework中内置TokenAuthentication 的一些问题。如何解决?
- 使用Knox,登录视图中的每一次调用都会生成令牌。这使得每个用户都有一个活跃的令牌,当用户注销时就会被删除。
- Knox在将令牌存储到数据库之前提供了一个加密的形式。即使数据库被破坏,这一功能也不允许任何黑客访问。
- 令牌过期也是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 内定义我们的线索模型。在这个模型中,每个线索将有像name 、email 、message 、最后是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端点,现在是时候通过只允许认证的用户执行HTTPGET 、POST 方法来保护它们。
我们将制作一个新的应用程序,名为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
下面是对每个类的解释。
至于RegisterAPI 和LoginAPI 类,由于我们使用的是基于类的视图,所以我们将先前制作的序列器提供给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互动之前,我们必须先注册,然后登录,我想你应该知道。
-
向
http://localhost:8080/api/leads和http://localhost:8080/api/user发出一个GET请求。由于用户没有登录,那么应该发送一个验证错误。 -
http://localhost:8080/api/auth/register现在向POST,并在正文中选择raw"JSON。为用户提供JSON对象,包括username,email, 和password。
响应将是一个令牌,将在登录时用于授权用户。见下面的图片。

Headers复制从注册中发送的令牌,并将其粘贴在Authorization的值部分,在其前面输入Token,如下所示。
现在用注册用户的username ,和password ,向http://localhost:8080/api/auth/login 发出一个POST 请求。登录后,将发送另一个新的令牌用于注销。

- 最后,向领导的API端点提出
GET,你将被允许访问它。这必须在令牌过期前完成。
总结
在本教程中,我们介绍了Django-Knox的实现。我们通过在用户认证和授权的基础上建立其余的API端点,展示了该框架的令牌智能性。