实战讲解 Django-rest-framework JWT 用户认证开发

2020-06-13 00:00:00 创建 用户 代码 复制 认证


我们用 Djangorest-framework 开发用户模块, 并使用 JWT(Json Web Token) 进行用户认证, 该项目将上传在 MedusaSorcerer/django-restframework-demo 上供大家借鉴和使用。

开发环境:Windows10
开发 IDE:Pycharm
开发框架:Django
开发语言:Python

requirements

python==3.8.2
django==3.0.6
django-restframework
django-restframesork-jwt
复制代码

创建 Django 项目

CMD 命令行界面, 创建 Django 项目程序 Medusa

python3 -m django startproject Medusa
复制代码

Medusa 根目录下创建应用总模块 applications

cd Medusa
mkdir applications
复制代码

进入 applications 创建应用模块 User, 这儿采用傻瓜式操作, 创建层级 Django-APP

cd applications
python3 ../manage.py startapp User
复制代码

此时项目结构如下:

修改配置

修改 applications/User/apps.py

from django.apps import AppConfig


class UserConfig(AppConfig):
    name = 'applications.User'
复制代码

在项目根目录新建配置文件夹 config, 并添加配置文件 config.py

cd ..
mkdir config
cd config
type NUL > config.py
复制代码

config/config.py 新增以下配置内容:

#!/usr/bin/env python
# _*_ Coding: UTF_8 _*_

# MySQL 服务地址
MYSQL_SERVER_HOST = '127.0.0.1'

# MySQL 服务端口
MYSQL_SERVER_PORT = '3306'

# MySQL 数据库名称
MYSQL_DATABASE_NAME = 'medusa'

# MySQL 数据库连接用户账号
MYSQL_SERVER_USERNAME = 'root'

# MySQL 数据库连接用户密码
MYSQL_SERVER_PASSWORD = 'mysql-password'
复制代码

修改 Medusa/settings.py 中配置参数 ALLOWED_HOSTS

ALLOWED_HOSTS = ['*']
复制代码

添加 Medusa/settings.py 中应用注册参数 INSTALLED_APPS

INSTALLED_APPS = [
    ...,
    'applications.User',
]
复制代码

Medusa/settings.py 顶部导入配置文件:

from config import config
复制代码

Medusa/setting.py 中修改配置数据库参数 DATABASES

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': config.MYSQL_DATABASE_NAME,
        'USER': config.MYSQL_SERVER_USERNAME,
        'PASSWORD': config.MYSQL_SERVER_PASSWORD,
        'HOST': config.MYSQL_SERVER_HOST,
        'PORT': config.MYSQL_SERVER_PORT,
    }
}
复制代码

Medusa/setting.py 中修改配置时区参数 TIME_ZONE:

TIME_ZONE = 'Asia/Shanghai'
复制代码

当然你可以继续在 Medusa/settings.py 修改语言参数, 我们创建的项目暂不修改:

LANGUAGE_CODE = 'zh-hans'
复制代码

确保你的 MySQL 中已经存在了你配置的数据库名称对应的数据库, 并且可以连接成功, 就可以尝试在 Medusa 根目录下启动 Django 项目,:

python3 manage.py runserver 0.0.0.0:8000
复制代码

你如果执行成功你可以访问 http://127.0.0.1:8000/ 就看到以下界面:

创建 User 模型

applications/User/models.py 中自定义我们的用户模型类

from django.contrib.auth.models import AbstractUser


class User(AbstractUser):
    class Meta:
        db_table = 'medusa_user'
        ordering = ('-id',)
复制代码

我们采用的是继承 AbstractUser 类并指定 db_table 的方式, 此时你可以使用 PycharmCtrl + B 进入父类中查看 User 具有的属性和方法。

当然了, 在执行到这个步骤的时候其实用户的模型类并没有生效, 而需要达到生效的效果则是需要指定用户模型类的位置参数, 你只需要在 Medusa/settings.py 中用 AppName.UserModelsName 的方式指定用户模型类即可:

AUTH_USER_MODEL = 'User.User'
复制代码

有关于用户认证的模型类介绍, 推荐你查阅 Customizing authentication in Django。

使用 Django 迁移命令迁移数据库生成数据表:

python3 manage.py makemigrations
python3 manage.py migrate
复制代码

你可以使用 MySQL 数据库连接应用查看你生成的数据表。

登录认证

在准备好基本环境后我们进行登录接口的开发工作, 登录的接口主要是对用户进行验证以及口令的返回, 使用 JWT 验证的时候先安装导入需要的包应用 rest_framework, 添加 Medusa/settings.py 中应用注册参数 INSTALLED_APPS

INSTALLED_APPS = [
    ...,
    'rest_framework',
]
复制代码

applications/User/ 下创建用户认证的视图文件 userauth.py 并撰写用户登录认证视图类:

#!/usr/bin/env python
# _*_ Coding: UTF-8 _*_
from rest_framework_jwt.serializers import JSONWebTokenSerializer
from rest_framework_jwt.views import JSONWebTokenAPIView


class UserLoginAPIView(JSONWebTokenAPIView):
    serializer_class = JSONWebTokenSerializer
复制代码

简简单单的几行代码就实现了一个用户登录的接口, 你现在就需要在你的路由管理器里面注册这个登录的 API 试图即可, 在 Medusa/urls.pyurlpatterns 参数中注册路由:

urlpatterns = [
    path('api/v1.0.0/user/login', userauth.UserLoginAPIView.as_view())
]
复制代码

不要着急, 我们是不是还没有创建用户呢?

python3 manage.py createsuperuser
复制代码

依次输入:

  1. Username
  2. Email address
  3. Password
  4. Password(again)

因为我输入的密码是 admin, 所以在创建的时候给了三个警告信息, 需要你确认信息后再次确认:

The password is too similar to the username.
This password is too short. It must contain at least 8 characters.
This password is too common.
复制代码
  • 密码和用户名的相似度过高
  • 密码长度太短, 应该至少是八个字符
  • 密码属于弱密码

不管他, 上去就是一个 y 给他:

是时候启动服务测试下我们的代码成果了:

登录注销

对于已经登录的用户实现登出功能, 主要的是在于登录的一种身份判断, 那等同于一个字段能实现判断登录用户登出后变化, 并且重新生成这个字段。

我们在 User 类中加入这样一条字段配置:

from uuid import uuid4

user_secret = models.UUIDField(default=uuid4())
复制代码

注意 user_secretUser 类的一个属性, 你可能会想那我是不是要重新实现哟用户登录的逻辑呢? 答案是不需要的, 因为我们创建的字段, 我们用函数路径的方式指定原先的函数, 我们将采用重写原本的判断函数即可实现:

在项目根目录下的 applications/User/views.py 中创建函数, 函数位置可自行确定, 你也可以创建一个 .py 文件:

#!/usr/bin/env python
# _*_ Coding: UTF-8 _*_


def get_user_secret(user):
    return user.user_secret
复制代码

主要的内容是在 Medusa/settings.py 中配置函数路径:

JWT_AUTH = {
    'JWT_GET_USER_SECRET_KEY': 'applications.User.views.get_user_secret'
}
复制代码

因为我们修改了模型类, 所以我们需要对数据库进行再次迁移:

python3 manage.py makemigrations
python3 manage.py migrate
复制代码

applications/User/userauth.py 中创建登出视图:

import uuid

from rest_framework import status, views
from rest_framework.response import Response


class UserLogoutAPIView(views.APIView):
    def get(self, request, *args, **kwargs):
        user = request.user
        user.user_secret = uuid.uuid4()
        user.save()
        return Response({'detail': 'login out.', 'status': status.HTTP_200_OK}, status=status.HTTP_200_OK)
复制代码

在路由模块 Medusa/urls.py 中注册:

urlpatterns = [
    ... ,
    path('api/v1.0.0/user/logout', userauth.UserLogoutAPIView.as_view()),
]
复制代码

测试一下:

NotImplementedError: Django doesn't provide a DB representation for AnonymousUser.
复制代码

What? 报错了, 因为我们访问 API 的时候没有使用认证信息, 所以访问的 User 对象是一个匿名用户对象, 所以我们需要对这个接口采取认证:

from rest_framework.permissions import IsAuthenticated


class UserLogoutAPIView(views.APIView):
    permission_classes = [IsAuthenticated]
    
    def get(self, request, *args, **kwargs):
        ...
复制代码

添加认证参数 permission_classes 表示需要 IsAuthenticated 已认证的对象才可以访问, 再次尝试接口会收到以下 json 提示:

{
    "detail": "Authentication credentials were not provided."
}
复制代码

认证失败? 我们在 Medusa/settings.py 中添加以下配置信息:

import datetime


JWT_AUTH = {
    # 之前配置的用户依据判断函数路由
    'JWT_GET_USER_SECRET_KEY': 'applications.User.views.get_user_secret',
    
    # 用户认证数据的过期时间
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1)
}
REST_FRAMEWORK = {
    # 用户认证类
    'DEFAULT_AUTHENTICATION_CLASSES': (
        # 优先使用 JWT 的方式认证用户
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
    ),
}
复制代码

{
    "detail": "login out.",
    "status": 200
}
复制代码

创建用户

在创建用户的时候我们不会使用命令行来创建用户的, 使用模型类的时候创建用户一般会这样来实现, 当然了, 这儿我们省略了一些操作, 仅仅介绍创建用户的快捷方式:

from applications.User.models import User


User.objects.create_user(username=username, email=email, password=password, **extra_fields)
User.objects.create_superuser(username=username, email=email, password=password, **extra_fields)
复制代码

后面携带的 **extra_fields 可以让你携带更多的 Models 指定的字段, 如果你需要的话。

该描述内容有些省略的地方或者描述不清的地方请留言
代码已经同步至 Github 地址:MedusaSorcerer/django-restframework-demo
今天你进步了吗?

相关文章