喵喵CRM很多地方写得乱七八糟,能用但是代码看起来实在很糟糕。
最近在写权限模块,想和之前客户模块对比对比,然而一对比才发现,之前写的简直就是一坨。而且之前部分地方是一边学一边写的,很冗余。遂打算重构下部分地方,主要是:登录登出、文件目录整理、视图重构、代码注释补充、程序主页、路由调整等,此外,为了进一步贯彻前后端分离逻辑,Django里面的templates页面就都给删除了,后续测试主要采用Apifox进行(之前一直没咋用,觉得页面直观一些。今天仔细用了一下,发现……真的方便)。
之前的注册、登录、登出是放在customer模块下面的,现在给独立出来,此外全部改用DRF,实现前后端分离。
注册
序列化器
from rest_framework import serializers
from django.contrib.auth.models import User
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
class Meta:
model = User
fields = ['username', 'password', 'first_name', 'last_name']
def create(self, validated_data):
"""
使用create_user覆写create函数,密码加密。
"""
user = User.objects.create_user(**validated_data)
return user
先介绍下父类:serializers.ModelSerializer,几乎所有的序列化都会用到。ModelSerializer 是 DRF 提供的一个类,可以(1)自定义方法(如 create)来实现更细粒度的控制。(2)自动处理模型字段的验证和序列化。(3)提供默认的 create 和 update 方法,适配模型实例的创建和更新。
这儿整体逻辑比较简单,需要注意的是密码特殊处理,write_only保证了密码只可POST接收值,不在GET中响应。而create方法重写,换成User.object.create_user可以保证密码哈希加密。
此外,DRF会默认一些安全措施:(1)身份验证机制,支持SessionAuthentication和TokenAuthentication。(2)CSRF保护,不过通常通过token认证来代替CSRF验证。不过在暴力破解、XSS攻击等方面仍有些欠缺。
有趣的是**validated_data这个写法,就是把 validated_data 这个字典里的每个键值对拆开,作为关键字参数传给 create_user 方法。
validated_data = {'username': 'john', 'password': 'securepassword'}
user = User.objects.create_user(**validated_data)
# 相当于:
user = User.objects.create_user(username='john', password='securepassword')
视图
from django.shortcuts import render
from django.contrib.auth import authenticate
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from .serializers import RegisterSerializer
from rest_framework_simplejwt.tokens import RefreshToken
from django.views import View
class RegisterView(APIView):
def post(self, request):
serializer = RegisterSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response({"message": "注册成功,请登录!"}, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
简单明了,获取数据、验证、存储。APIView后续会具体对比分析下,这儿先默认使用。
登录
登录仅仅需要对比下账户和密码,无需序列化器。
视图
class LoginView(APIView):
def post(self, request):
username = request.data.get('username')
password = request.data.get('password')
user = authenticate(username=username, password=password)
if user is not None:
refresh = RefreshToken.for_user(user)
return Response({
'refresh': str(refresh),
'access': str(refresh.access_token),
})
return Response({"error": "用户名或密码错误"}, status=status.HTTP_401_UNAUTHORIZED)
authenticate可以检查登录名和密码是否匹配,不匹配返回None。RefreshToken则是DRF的一个扩展库, Simple JWT 的一部分。Simple JWT 是专门用于生成和验证 JSON Web Tokens (JWT)。
JWT是一种用于在网络应用环境中安全地传递声明的开放标准,它通常用于身份认证和信息交换。JWT 是一种自包含的令牌格式,意味着它包含了所有用户认证和验证所需的信息,而无需查询数据库。简单来说,一个用于前后端认证的工具,省的每次访问都去查询数据库,同时具备一定的安全性。这儿会有两个token,refresh和access,一个稍微长期、一个短期。access失效了就用refresh再去要个access。
登出
视图
class LogoutView(APIView):
def post(self, request):
response = Response({"message": "登出成功"})
response.delete_cookie('access_token')
return response
路由
from django.urls import path
from .views import RegisterView, LoginView, LogoutView
urlpatterns = [
path('register/', RegisterView.as_view(), name='register'),
path('login/', LoginView.as_view(), name='login'),
path('logout/', LogoutView.as_view(), name='logout'),
]