1、注册、登陆接口-简单设计
1.1、创建用户注册表的模型类
from django.db import modelsfrom django.core.paginator import Paginator# Create your models here.class NewUser(models.Model):phone = models.CharField(verbose_name="手机号",max_length=11,unique=True)email = models.EmailField(verbose_name="邮箱",max_length=50,unique=True)nick = models.CharField(verbose_name="昵称", max_length=50)password = models.CharField(verbose_name="密码",max_length=32)class Meta:verbose_name = "用户表"verbose_name_plural = verbose_namedb_table = "new_user" # 映射的用户注册表名称def __str__(self):return self.nick
- 检查这个模型所在的app是否注册,没有注册,在settings.py配置文件中,完成注册
- 数据迁移:
- 生成迁移文件 python manage.py makemigrations
- 执行迁移脚本程序 python manage.py migrate
- 连接数据库,检查数据表是否创建成功

1.2、注册、登陆接口视图函数
import hashlibimport jsonimport timeimport django_redisfrom django.forms import model_to_dictfrom django.http import JsonResponsefrom django.db.models import Qfrom django.shortcuts import renderfrom . import models# Create your views here.# 注册接口def register(request):email = request.POST.get("email")nick = request.POST.get("nick")phone = request.POST.get("phone")password = request.POST.get("password")password2 = request.POST.get("password2")if email and nick and phone and password:if password != password2:return JsonResponse({"code": -1, "msg": "两次输入的密码不一致"})user_email = models.NewUser.objects.filter(email=email)user_phone = models.NewUser.objects.filter(phone=phone)if user_email.exists():return JsonResponse({"code": -1, "msg": "email exists"})if user_phone.exists():return JsonResponse({"code": -1, "msg": "phone exists"})new_password = md5(password)user = models.NewUser(email=email, nick=nick, phone=phone, password=new_password)user.save()return JsonResponse({"code": 0, "msg": "success"})else:return JsonResponse({"code": -1, "msg": "not null"})# 登陆接口def login2(request):username = request.POST.get("username") # email + password ; phone+passwordpassword = request.POST.get("password")if username and password:user = models.NewUser.objects.filter(Q(email=username) | Q(phone=username))if not user.exists():return JsonResponse({"code": -1, "msg": "user not exists"})if user.first().password != md5(password):return JsonResponse({"code": -1, "msg": "password error"})#todo:这里要校验当前用户是否已经登录,如果已经登录,那么直接返回token (用来解决重复登陆存储多个token的问题)token = md5(str(time.time()) + username)user_dict = json.dumps(model_to_dict(user.first()))r = django_redis.get_redis_connection()expire_time = 60 * 60 * 24 * 1 # session的过期时间r.set(token, user_dict, expire_time)return JsonResponse({"code": 0, "msg": "login success", "token": token})else:return JsonResponse({"code": -1, "msg": "not null"})def md5(s):s = str(s)m = hashlib.md5(s.encode())return m.hexdigest()
配置路由
"""thz_django URL ConfigurationThe `urlpatterns` list routes URLs to views. For more information please see:https://docs.djangoproject.com/en/3.2/topics/http/urls/Examples:Function views1. Add an import: from my_app import views2. Add a URL to urlpatterns: path('', views.home, name='home')Class-based views1. Add an import: from other_app.views import Home2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')Including another URLconf1. Import the include() function: from django.urls import include, path2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))"""from django.contrib import adminfrom django.urls import pathfrom user_demo import views as user_demo_viewurlpatterns = [path('admin/', admin.site.urls),path('user_demo/register', user_demo_view.register), # 绑定路由和视图path('user_demo/login', user_demo_view.login2),]
验证注册接口
验证登陆接口

bug:短时间再次登陆,再次返回一个新的token,并存储到Redis中
1.3、解决重复登陆,Redis存储多个token的问题
- 登陆成功,给Redis存储两条记录
- 一条记录记录用户名和token,例如 (15503129999:”4a546a5e7b90adf7aa16a091006931e0”)
- 一条记录token和用户信息,例如(”4a546a5e7b90adf7aa16a091006931e0”:用户信息)
# 登陆接口def login2(request):username = request.POST.get("username") # email + password ; phone+passwordpassword = request.POST.get("password")if username and password:user = models.NewUser.objects.filter(Q(email=username) | Q(phone=username))if not user.exists():return JsonResponse({"code": -1, "msg": "user not exists"})if user.first().password != md5(password):return JsonResponse({"code": -1, "msg": "password error"})#todo:这里要校验当前用户是否已经登录,如果已经登录,那么直接返回token (用来解决重复登陆存储多个token的问题)user_key = "session_wxj:%s"%user.first().phone# 登陆时,给Redis中存储两条记录 (用户名:token)(token:用户信息)#r = django_redis.get_redis_connection()redis_token = r.get(user_key)if redis_token:# 如果Redis中有这个用户的登陆记录就返回上一次登陆获取的tokenreturn JsonResponse({"code": 0, "msg": "login success", "token": redis_token.decode()})#token = md5(str(time.time()) + username) # 如果没有登陆记录,就重新返回新的tokenuser_dict = json.dumps(model_to_dict(user.first()))r = django_redis.get_redis_connection()expire_time = 60 * 60 * 24 * 1 # session的过期时间#r.set(user_key, token, expire_time)# 登陆时,给Redis中存储两条记录 (用户名:token)(token:用户信息)#r.set(token, user_dict, expire_time)return JsonResponse({"code": 0, "msg": "login success", "token": token})else:return JsonResponse({"code": -1, "msg": "not null"})
2、中间件-校验token
from django.middleware.common import MiddlewareMixinfrom django.http.response import HttpResponse, JsonResponseimport django_redisimport jsonno_login_urls = ["login", "register", "admin"] # 不需要校验token的接口相关class TokenMiddleWare(MiddlewareMixin):"""校验接口是否需要传token的中间件"""def check_not_url(self, path): # /api/loginfor url in no_login_urls:if url in path:# 模糊匹配,URL中包含这个就不校验tokenreturn Truedef process_request(self, request):# 执行路由之前被调用login_tag = self.check_not_url(request.path_info)if login_tag != True:token = request.GET.get("token")if not token:return JsonResponse({"code": -1, "msg": "没有传token"})r = django_redis.get_redis_connection()login_user = r.get(token)if not login_user:return JsonResponse({"code": -1, "msg": "token已失效"})request.user = json.loads(login_user) # 给request对象里面增加user属性# token = reuqest.headers.get("token")# request.path_info /login /api/register# 1、先判断url是否需要登录,需要登录才校验token# 2、在判断是否传了token# 3、再判断在redis里面是否有token# def process_response(self,request,response):# print("process_response")# response["aaaaa"] = "111111"# return response# def process_exception(self,request,exception):# print("exception",exception)# return
注意:
别忘了在settings.py配置文件中,注册这个中间件


