Django REST framework 和 Simple JWT 实现小程序的用户注册、登录和身份验证

Django REST framework 和 Simple JWT 实现小程序的用户注册、登录、认证以及自动刷新过期的Access Token。文章分为后端和小程序两部分,后端开发使用VSCode,小程序开发使用微信开发工具。

一、在创建好的Django应用上安装djangorestframework-simplejwt

pip install djangorestframework-simplejwt
<code>官方参考文档https://django-rest-framework-simplejwt.readthedocs.io/en/latest/index.html</code>
<code>setting.py</code><code><br></code><code>REST_FRAMEWORK = {</code><code> 'DEFAULT_AUTHENTICATION_CLASSES': [</code><code> ...</code><code> 'rest_framework_simplejwt.authentication.JWTAuthentication', <em># 使用rest_framework_simplejwt(token)验证身份</em></code><code>         ...</code><code>     ]</code><code> }</code><code><br></code><code><em># JWT自定义配置</em></code><code>SIMPLE_JWT = {</code><code> 'ACCESS_TOKEN_LIFETIME': timedelta(days=7), <em># 配置过期时间</em></code><code> 'REFRESH_TOKEN_LIFETIME': timedelta(days=15),</code><code> 'JWT_ALLOW_REFRESH': True, <em># 是否允许用户获取新的token值</em></code><code>}</code><code></code>

三、后端用户数据表models.py

<code>from django.db import models</code><code><br></code><code><em># Create your models here.</em></code><code>from django.contrib.auth.models import AbstractUser</code><code><br></code><code>class UserProfile(AbstractUser):</code><code> name = models.CharField(max_length=30, blank=True, null=True, verbose_name='姓名', help_text='姓名')</code><code> birthday = models.DateField(null=True, blank=True, verbose_name='出生年月', help_text='出生年月')</code><code> mobile = models.CharField(max_length=11, verbose_name='电话', help_text='电话',blank=True, null=True)</code><code> avatar_url = models.CharField(max_length=225, verbose_name="头像", default="")</code><code> gender = models.CharField(max_length=6, choices=(('male', '男'), ('female', '女'),('unknow', '未知')), default='unknow', verbose_name='性别', help_text='性别')</code><code> class Meta:</code><code> verbose_name_plural = verbose_name = '用户'</code><code><br></code><code>    def __str__(self):</code><code>         return self.username</code>

四、urls.py

<code>urlpatterns = [</code><code> ...</code><code> path('wxlogin/', WxLogin.as_view(), name='wxlogin'),<em># simplejwt认证接口</em></code><code>    path('refresh/', WxRefresh.as_view(), name='refresh'),<em># access刷新接口</em></code><code>    ...</code><code>    ]</code>

五、views.py视图

<code>from rest_framework_simplejwt.tokens import RefreshTokenfrom rest_framework.views import APIViewfrom rest_framework.response import Responsefrom utils.WXLogin import GetProfileimport json<br>User = get_user_model()<br>class WxLogin(APIView): def post(self, request, format=None): """ 提供 post 请求 """ <em># 从请求中获得code</em> code = json.loads(request.body).get('jscode') iv = json.loads(request.body).get('iv')        encryptedData = json.loads(request.body).get('encryptedData')        result = GetProfile(code, encryptedData, iv) openid = result['openid']        pResult = result['pResult'] try: user = User.objects.get(username=openid) except User.DoesNotExist: user = None        if user:            refresh = RefreshToken.for_user(user) return Response({ 'code': '200', 'refresh': str(refresh), 'access': str(refresh.access_token), 'userinfo':{ 'userid': user.id, 'name': user.name, 'avatar_url': user.avatar_url, 'mobile': user.mobile, 'username': user.username } }) else: user = User.objects.create( username=openid, password=openid, name=pResult["nickName"], avatar_url=pResult["avatarUrl"],                gender=pResult["gender"], )            refresh = RefreshToken.for_user(user) return Response({ 'code': '200', 'refresh': str(refresh), 'access': str(refresh.access_token), 'userinfo':{ 'userid': user.id, 'name': user.name, 'avatar_url': user.avatar_url, 'username': user.username                }                 })<br>class WxRefresh(APIView):    def post(self, request): refresh = json.loads(request.body).get('refresh')        access = RefreshToken(refresh) return Response({ 'code': '200', 'refresh': str(access), 'access':str(access.access_token) })</code>
<code>import requests</code><code>import json</code><code>from utils.WXBizDataCrypt import WXBizDataCrypt</code><code>appid = ''<em>#小程序appid</em></code><code>appsecret = '' <em>#小程序appsecret</em></code><code><em># 微信接口服务地址</em></code><code>base_url = 'https://api.weixin.qq.com/sns/jscode2session'</code><code>def GetProfile(code,encryptedData,iv):</code><code> <em># 微信接口服务的带参数的地址</em></code><code> url = base_url + "?appid=" + appid + "&secret=" + appsecret + "&js_code=" + code + "&grant_type=authorization_code"</code><code> response = requests.get(url)</code><code> try:</code><code> openid = response.json()['openid']</code><code> session_key = response.json()['session_key']</code><code> wxdc = WXBizDataCrypt(appid, session_key)</code><code> pResult = wxdc.decrypt(encryptedData, iv)</code><code> result={"openid":openid,"pResult":pResult}</code><code> return result</code><code> except KeyError:</code><code> msg = "数据错误,请重新尝试"</code><code> return msg</code>

上述完成后端部分的开发,初始化完数据库既可启动Django服务。接着进入到小程序开发。

七、小程序开发主要是js下的逻辑开发,其他部分自行操作,小程序开发要引入一个好用时间库dayjs,非常好用,大家不熟悉的可以直接去可以访问其官网,有详细教程。https://dayjs.fenxianglu.cn/category/

1、小程序登录

<code>import dayjs from '../../utils/dayjs.min.js'</code><code><br></code><code>getUserProfile(e) {</code><code> <em>// 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认,开发者妥善保管用户快速填写的头像昵称,避免重复弹窗</em></code><code> wx.getUserProfile({</code><code> desc: '展示用户信息', <em>// 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写</em></code><code>      success: (res) => {</code><code> wx.login({</code><code>          success: (res2) => {</code><code> wx.request({</code><code>              url: 'https://你的域名/wxlogin/',</code><code> method: 'POST',</code><code> data: {</code><code> jscode: res2.code,</code><code> iv: res.iv,</code><code> encryptedData: res.encryptedData,</code><code> },</code><code>              success: res => {</code><code>                if (res.data.code == 200) {</code><code> wx.setStorage({</code><code> key:'access',</code><code>                    data: res.data.access,</code><code>                 })</code><code>                 wx.setStorageSync('userInfo', res.data.userinfo)</code><code>                 wx.setStorageSync('refresh', res.data.refresh)</code><code>                 wx.setStorageSync('access_time', dayjs())</code><code> this.setData({</code><code>                    userInfo: res.data.userinfo,</code><code> })</code><code> wx.showToast({</code><code> title: '登录成功',</code><code> icon: 'success',</code><code> duration: 2000</code><code> })</code><code> } else {</code><code> wx.showToast({</code><code> title: '请重新登录',</code><code> icon: 'error',</code><code> duration: 2000</code><code> })</code><code> }</code><code> }</code><code> })</code><code> }</code><code>        })</code><code> }</code><code> })</code><code> },</code>

2、假如access过期,这里需要用到时间判断是否超过后端配置的access有效期时间,本例中为七天。

<code>import dayjs from '../../utils/dayjs.min.js'</code><code><br></code><code>OnSubmit:function(){</code><code>    var now= dayjs</code><code>    var access_time= wx.getStorageSync('access_time')</code><code>    var refresh = wx.getStorageSync('refresh')</code><code>    if(dayjs(access_time).add(7, 'day') <= now){</code><code>        wx.request({</code><code>              url: 'https://你的域名/refresh/',</code><code> method: 'POST',</code><code> data: {</code><code> refresh:refresh</code><code> },</code><code>              success: res => {</code><code>               wx.setStorage({</code><code> key:'access',</code><code>                    data: res.data.access,  </code><code>                 })</code><code>                  wx.setStorageSync('refresh', res.data.refresh)</code><code>                   wx.setStorageSync('access_time', dayjs())</code><code>              }</code><code>    }</code><code> wx.getStorage({<em>//获取本地缓存</em></code><code> key:"access",</code><code> success:function(res){</code><code> var access=res.data</code><code> }</code><code>    })</code><code> }</code>

每次调用access向后端发送请求时,前判断access_time是否超过7天,超过7天即自动刷新获取access。此判断方法可以写成一个函数,供其他页面使用。

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容