Django使用DRF + Simple JWT 完成小程序使用自定义用户的注册、登录和认证
在已经配置好djangorestframework-simplejwt的前提下进行
模型类及序列化器
小程序用户模型类
这里的模型类并未继承django自带的用户模型类,好处是后面小程序用户也是没法进行admin端的,缺点是可能会对django自带的权限管理有影响,如果只有小程序端的用户的话没问题,但是如果还有其它用户的话就可能会出问题,因为在这个模型中是没有密码存在的,只要拿到小程序端生成的用户的code就能够通过登录接口获取到用户的token(小程序端的code每次生成是不同的,有效期应该是5分钟)
class User(models.Model):
USER_TYPE = ((1, '顾客'),
(2, '商家'))
GENDER = ((0, '男'),
(1, '女'),
(2, '未知'))
username = models.CharField('用户名', max_length=20, blank=True)
tel = models.BigIntegerField('手机号', unique=True, blank=True, null=True)
openid = models.CharField('小程序openid', unique=True, max_length=100, blank=True, null=True)
avatar_url = models.URLField('头像', help_text='头像', null=True, blank=True)
unionid = models.CharField('小程序unionid', unique=True, max_length=100, blank=True, null=True)
nickname = models.CharField('微信昵称', max_length=100, blank=True, null=True)
gender = models.IntegerField('性别', choices=GENDER, default=2)
type = models.IntegerField('用户类型', choices=USER_TYPE, default=1)
# 用自定义的用户需要重写此方法
@property
def is_authenticated(self):
"""
Always return True. This is a way to tell if the user has been
authenticated in templates.
"""
return True
def __str__(self):
return self.openid
class Meta:
db_table = 'user'
verbose_name = '用户管理'
verbose_name_plural = verbose_name
小程序用户序列化器
小程序用户表中的所有信息,当然可以自己去模型类中加一些,像注册时间或者是更新时间,上次登录时间等,此处只是演示,并未添加
class UserSerializer(serializers.ModelSerializer):
"""用户序列化器"""
class Meta:
model = User
fields = '__all__'
自定义认证类
主要其实是用来获取到用户,其它的方法都是继承了simplejwt的JWTAuthentication中的方法。
在用户app目录下直接去新建一个文件 Authentication.py 写入如下内容
from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework_simplejwt.exceptions import InvalidToken, AuthenticationFailed
from apps.user.models import User
# 自定义的解析token的方法 下面会用到
from utils.token_get_user import get_user
class MyJWTAuthentication(JWTAuthentication):
"""
继承JWTAuthentication类, 返回自定义User对象
"""
# get_user用于返回用户,重写后在其它地方使用request.user时可以直接得到自定义的小程序用户
def get_user(self, validated_token):
try:
user_id = get_user_id(str(validated_token)) # 此处为自定义的解析token方法, 可以解码token得到其中的信息,重点是拿到user_id 用于后续的获取用户
except KeyError:
raise InvalidToken(_('Token不包含可识别的用户标识'))
try:
user = User.objects.get(**{'id': user_id})
except User.DoesNotExist:
raise AuthenticationFailed(_('未找到用户'), code='user_not_found')
return user
get_user_id方法: 用于解析我们的token得到user_id
import jwt
import time
# ConvLife为我的项目名称,此处导入的是项目的settings,主要是拿到自定义的secret_key
from ConvLife import settings
def get_user_id(t):
"""根据token得到当前用户user_id"""
try:
decode_data = jwt.decode(t, secret_key=settings.SECRET_KEY, verify=False, algorithms=['HS256'])
print(decode_data)
if int(decode_data['exp']) < int(time.time()):
return "token过期"
return decode_data['user_id']
except Exception as e:
return "token错误:\n"+str(e)
小程序登录及手动签发token
用户视图
在登录这其实就是重写了create,思路大概:通过用户传入的code获取到openid(获取不到openid的情况就是code出错或者用户未输传入code),然后使用openid去用户表查找用户,如果不存在则新建,存在则读取到,然后针对读取或者新建的用户生成一个token,再返回给前端
# get_wx_openid 是调用微信开放接口,使用小程序传到后端的code去请求openid,openid作为唯一标识
from utils.wx import get_wx_openid
from utils.Authentication import MyJWTAuthentication
class WxLogin(mixins.CreateModelMixin, viewsets.GenericViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
def create(self, request, *args, **kwargs):
# code是小程序端可以直接获取到的,获取到后和userinfo一起Post到后端
code = request.data.get('code', '')
# 通过传入的code来获取openid
openid_res = get_wx_openid(code)
try:
openid = openid_res['openid'] or ''
except KeyError as e:
return Response({'message': '微信调用失败'}, status=status.HTTP_503_SERVICE_UNAVAILABLE)
# 尝试查找用户,如果用户存在则读取用户,用户不存在则新建用户
try:
user = User.objects.get(openid=openid)
except User.DoesNotExist:
# userinfo 是小程序端可以直接获取到的,获取到后和code 一起Post到后端
user_info = request.data.get('userInfo')
print(user_info)
user = User.objects.create(openid=openid,
avatar_url=user_info['avatarUrl'],
nickname=str(user_info['nickName']),
gender=user_info['gender'])
user.save()
# 手动签发jwt token
refresh = RefreshToken.for_user(user)
resp_data = {
'user_id': user.id,
"refresh": str(refresh),
"access": str(refresh.access_token)
}
return Response(resp_data)
路由
这里直接配置成前端发送code和userinfo来请求的了,需要测试的话请求得先去在微信小程序端获取到code,要带着code去请求,不然会报错!
from .views import WxLogin
router = routers.SimpleRouter()
# 小程序用户
router.register(r'login/', WxLogin, basename="login")
urlpatterns = router.urls
使用错误code获取token,失败
使用正确code获取token,成功
使用
在需要小程序用户登录验证的视图中加入permission_classes = [permissions.IsAuthenticated]
和authentication_classes = (MyJWTAuthentication,)
,当获取用户收藏或者收藏时就会需要用户是登录用户并会使用我们自定义的类,在登录的视图类中不要加哦,只是在需要验证的视图类中加上。
例如:文章来源:https://www.toymoban.com/news/detail-499247.html
from rest_framework import mixins
from rest_framework.permissions import IsAuthenticated
from .models import UserFav
from .serializers import UserFavSerializer
from utils.Authentication import MyJWTAuthentication
class UserFavViewSet(mixins.CreateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet):
"""
create: 用户收藏藏品
取消收藏商品
list: 获取收藏藏品列表
"""
queryset = UserFav.objects.all()
serializer_class = UserFavSerializer
permission_classes = [IsAuthenticated] # 增加此行
authentication_classes = [MyJWTAuthentication, ] # 增加此行
filter_backends = [DjangoFilterBackend, filters.SearchFilter]
search_fields = ('goods__good_name', 'goods__goods_brief')
# 获取到当前用户的收藏列表
def get_queryset(self):
return UserFav.objects.filter(user=self.request.user.id)
新手写博客,主要想记录下自己学习中遇到的问题及解决的过程,很多不足的地方,如有讲得不明白的地方看官请见谅,也可以私信我,看到后会尽快回复的文章来源地址https://www.toymoban.com/news/detail-499247.html
到了这里,关于Django使用DRF + Simple JWT 完成小程序使用自定义用户的注册、登录和认证的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!