drf之自定义User表与自定义认证类

自定义user表签发token

  普通写法,写在view类中

复制代码
from rest_framework.views import APIView
# class UserView(APIView):
# 自动生成路由,
from rest_framework.viewsets import ViewSetMixin
from rest_framework.decorators import action
from rest_framework.generics import GenericAPIView
from .models import UserInfo
from .serializer import UserInfoSerializer
from rest_framework.response import Response
from rest_framework_jwt.settings import api_settings

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER


# /user/login/--->post请求
# class UserView(ViewSetMixin, APIView):
#     @action(methods=['POST'], detail=False)
#     def login(self, request):
#         res_dic = {'code': 100, 'msg': '成功'}
#         username = request.data.get('username')
#         password = request.data.get('password')
#         user = UserInfo.objects.filter(username=username, password=password).first()
#         if user:  # 登陆成功
#             # 签发token?如何签发?--》去jwt源码中扣
#             payload = jwt_payload_handler(user)  # 得到荷载--》字典
#             print(payload)
#             token = jwt_encode_handler(payload)  # 通过荷载得到token串
#             res_dic['token'] = token
#             res_dic['username'] = user.username
#             return Response(res_dic)
#         else:
#             res_dic['code'] = 101
#             res_dic['msg'] = '用户名或密码错误'
#             return Response(res_dic)
复制代码

  逻辑写在序列化类中

    视图函数

复制代码
# 换种写法,写上面的登录,所有校验规则,写在序列化类中---》这种用的多
class UserView(ViewSetMixin, APIView):
    @action(methods=['POST'], detail=False)
    def login(self, request):
        res_dic = {'code': 100, 'msg': '成功'}
        ser = UserInfoSerializer(data=request.data,context={'request':request})
        if ser.is_valid():  # 这句话会走:字段自己的校验规则,局部钩子,全局钩子
            token = ser.context.get('token')
            username = ser.context.get('username')
            # token = ser.token
            # username = ser.username
            res_dic['token'] = token
            res_dic['username'] = username
        else:
            res_dic['code'] = 101
            res_dic['msg'] = ser.errors
        return Response(res_dic)
复制代码

    序列化类

复制代码
class UserInfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserInfo
        fields = ['username', 'password']  # 根据表模型中写的,字段自己有校验规则

    def validate(self, attrs):
        # 打印请求方式?
        print(self.context.get('request').method)
        # 签发token逻辑,签发生成token,放到ser.context字典中
        username = attrs.get('username')
        password = attrs.get('password')
        user = UserInfo.objects.filter(username=username, password=password).first()
        if user:  # 登陆成功
            payload = jwt_payload_handler(user)  # 得到荷载--》字典
            token = jwt_encode_handler(payload)  # 通过荷载得到token串
            # serializer和视图类沟通的桥梁
            self.context['token'] = token
            self.context['username'] = user.username
            # self.token=token
            # self.username=username
        else:
            raise ValidationError('用户名或密码错误')
        return attrs
复制代码

自定义认证类

复制代码
from rest_framework.authentication import BaseAuthentication
from rest_framework_jwt.settings import api_settings
from rest_framework.exceptions import AuthenticationFailed
import jwt
# from django.utils.translation import ugettext as _
from .models import UserInfo
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
class JWTAuthentication(BaseAuthentication):
    def authenticate(self, request):
        # 第一步:取出传入的token--》从哪去?--》咱们定的:请求地址?请求头?
        # token=request.query_params.get('token')# 请求地址?
        # http请求头中的数据,在META中,统一变成  HTTP_请求头的key大写
        jwt_value=request.META.get('HTTP_TOKEN')
        if jwt_value:
            # 验证token:是否过期,是否被篡改--》去源码扣
            try:
                payload = jwt_decode_handler(jwt_value)
            except jwt.ExpiredSignature:
                msg = '签名过期'
                raise AuthenticationFailed(msg)
            except jwt.DecodeError:
                msg = '签名被篡改'
                raise AuthenticationFailed(msg)
            except jwt.InvalidTokenError:
                raise AuthenticationFailed('未知错误')

            # 通过payload获得当前登录用户
            user = UserInfo.objects.filter(pk=payload['user_id']).first()

            return (user, jwt_value)
        else:
            raise AuthenticationFailed('您没有携带token')
复制代码

simpleui的快速使用

复制代码
# django-admin混合开发--》后台管理---》美化--》simpleui

# 使用步骤:
    -安装:pip3 install django-simpleui
  -注册app
    INSTALLED_APPS = [
      'simpleui',
    ]
  -定制左侧菜单
      SIMPLEUI_CONFIG = {
    'system_keep': False,
    'menu_display': ['监控大屏','应用1', '权限认证', '测试', '动态菜单测试'],  # 开启排序和过滤功能, 不填此字段为默认排序和全部显示, 空列表[] 为全部不显示.
    'dynamic': True,  # 设置是否开启动态菜单, 默认为False. 如果开启, 则会在每次用户登陆时动态展示菜单内容
    'menus': [
        {
            'name': '监控大屏',
            'icon': 'fas fa-code',
            'url': '/index/'
        },
        {
            'app': 'app01',
            'name': '应用1',
            'icon': 'fas fa-user-shield',
            'models': [
                {
                    'name': '图书',
                    'icon': 'fa fa-user',
                    'url': 'app01/book/'
                },
                {
                    'name': '用户',
                    'icon': 'fa fa-user',
                    'url': 'app01/userinfo/'
                }
            ]
        },
        {
            'app': 'auth',
            'name': '权限认证',
            'icon': 'fas fa-user-shield',
            'models': [
                {
                    'name': '用户',
                    'icon': 'fa fa-user',
                    'url': 'auth/user/'
                },
                {
                    'name': '用户组',
                    'icon': 'fa fa-user',
                    'url': 'auth/group/'
                }
            ]
        },
        {
            # 自2021.02.01+ 支持多级菜单,models 为子菜单名
            'name': '测试',
            'icon': 'fa fa-file',
            # 二级菜单
            'models': [{
                'name': 'Baidu',
                'icon': 'far fa-surprise',
                # 第三级菜单 ,
                'models': [
                    {
                        'name': '爱奇艺',
                        'url': 'https://www.iqiyi.com/dianshiju/'
                        # 第四级就不支持了,element只支持了3级
                    }, {
                        'name': '百度问答',
                        'icon': 'far fa-surprise',
                        'url': 'https://zhidao.baidu.com/'
                    }
                ]
            }, {
                'name': '内网穿透',
                'url': 'https://www.wezoz.com',
                'icon': 'fab fa-github'
            }]
        },
        {
            'name': '动态菜单测试',
            'icon': 'fa fa-desktop',
            'models': [{
                'name': time.time(),
                'url': 'http://baidu.com',
                'icon': 'far fa-surprise'
            }]
        }
    ]
}
  -自带权限
  -自定义左侧菜单的页面显示
      -通过混合开发,编写路径,配置到上面即可
  -更多操作见官方
复制代码

 

posted @   临江沂水  阅读(98)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示