【Django-rest-framework框架】 第12回 simpleui 集成监控大屏与restframework-jwt执行流程分析

1. 后台管理simpleui的介绍和使用

1. django admin自带了权限控制,但是是前后端混合的,我们可以二次开发,如开发出公司内部的自动化运行,自动化测试,人事管理系统,订单系统....页面样子不好看
2. 对django admin进行美化
   xadmin(不用了,过时了)
   simpleui(正红)
3. 基于drf+vue 自己写前后端分离的权限管理
4. djangio-vue-admin(gin-vue-admin)
   官方网址:https://django-vue-admin.com/document/
5. simpleui 
   参考指南:https://simpleui.72wo.com/docs/simpleui/QUICK.html#%E7%9B%AE%E5%BD%95


2. simple ui 的使用

1. 安装 
   pip install django-simpleui
2. 修改默认后台模板为simpleui
   在项目中的settings.py文件中加入一行simpleui即可
3. 创建用户账号 createsuperuser
4. 运行登录
5. 根据文档选择要实现的效果 
   https://simpleui.72wo.com/docs/simpleui/QUICK.html#%E7%9B%AE%E5%BD%95

2.1 自定义菜单

根据文档复制自定义菜单代码到 settings.py,如果修改代码,不显示效果,需要重启登录

import time

SIMPLEUI_CONFIG = {
    'system_keep': False,
    'menu_display': ['我的首页', '图书管理','权限认证', '多级菜单测试', '动态菜单测试'],  # 开启排序和过滤功能, 不填此字段为默认排序和全部显示, 空列表[] 为全部不显示.
    'dynamic': True,  # 设置是否开启动态菜单, 默认为False. 如果开启, 则会在每次用户登陆时动态展示菜单内容
    'menus': [
        {
            'name': '我的首页',
            'icon': 'fas fa-code',
            'url': '/index/',

        },
        {
            'app': 'app01',
            'name': '图书管理',
            'icon': 'fas fa-code',
            'models': [
                {
                    'name': '用户',
                    'icon': 'fa fa-user',
                    'url': 'app01/userinfo/'
                },
                {
                    'name': '图书',
                    'icon': 'fa fa-user',
                    'url': 'app01/book/'
                },
                {
                    'name': '出版社',
                    'icon': 'fa fa-user',
                    'url': 'app01/publish/'
                },
            ]
        },
        {
            'app': 'auth',
            'name': '权限认证',
            'icon': 'fas fa-user-shield',
            'models': [{
                'name': '用户',
                'icon': 'fa fa-user',
                'url': 'auth/user/'
            }]
        },
        {
            # 自2021.02.01+ 支持多级菜单,models 为子菜单名
            'name': '多级菜单测试',
            'icon': 'fa fa-file',
            # 二级菜单
            'models': [
                {
                    'name': '百度',
                    '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': 'lqz',
                    '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'
            }]
        }]
}


SIMPLEUI_LOGIN_PARTICLES = False
SIMPLEUI_HOME_INFO = False



2.2 配置首页 监控大屏

1. 搜索大屏模板,下载下来,复制写好的index.html文件
   gitee: https://search.gitee.com/?skin=rec&type=repository&q=%E7%9B%91%E6%8E%A7%E5%A4%A7%E5%B1%8F

2. 创建static文件,配置文件中配置
    STATIC_URL = '/static/'
    STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'),
    ]

3. 刷新或重启首页

3. restframework-jwt执行流程分析


# 签发的token,有过期时间,过期时间是?配置一般设为7天
JWT_AUTH = {
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),
}

# 双token认证
	-用户正在app或者应用中操作 token突然过期,此时用户不得不返回登陆界面,重新进行一次登录,这种体验性不好,于是引入双token校验机制
    -实现原理:首次登陆时服务端返回两个token ,accessToken和refreshToken,accessToken过期时间比较短,refreshToken时间较长,且每次使用后会刷新,每次刷新后的refreshToken都是不同

   
    
    -refreshToken假设7天,accessToken过期时间5分钟
    -正常使用accessToken即可,如果accessToken过期了,重新发请求,携带refreshToken过来,能正常返回,并且这次响应中又带了acessToken


    
# django中顶格写的代码,都会执行
    
# 签发流程--》本质就是登录接口---》【校验用户是否正确,如果正确签发token】写到了序列化类中,如果不正确返回错误
	-obtain_jwt_token:核心代码--ObtainJSONWebToken.as_view()
    -ObtainJSONWebToken 视图类,实现了登录功能
    class ObtainJSONWebToken(JSONWebTokenAPIView):
    	serializer_class = JSONWebTokenSerializer


    -父类ObtainJSONWebToken
    class JSONWebTokenAPIView(APIView):
        # 局部禁用掉权限和认证
        permission_classes = () 
        authentication_classes = ()

        def get_serializer_context(self):
            return {
                'request': self.request,
                'view': self,
            }

        def get_serializer_class(self):
            return self.serializer_class

        def get_serializer(self, *args, **kwargs):
            serializer_class = self.get_serializer_class()
            kwargs['context'] = self.get_serializer_context()
            return serializer_class(*args, **kwargs)

        def post(self, request, *args, **kwargs):
            # JSONWebTokenSerializer实例化得到一个序列号类的对象,传入前端传的只
            serializer = self.get_serializer(data=request.data)

            if serializer.is_valid(): # 校验前端传入的数据是否合法:
                #1 字段自己的规则 2 局部钩子 3 全局钩子(序列化类的validate方法)
                # 获取当前登录用户和签发token是在序列化类中完成的
                # 从序列化类对象中取出了当前登录用户
                user = serializer.object.get('user') or request.user
                # # 从序列化类对象中取出了token
                token = serializer.object.get('token')
                # 自定义过
                response_data = jwt_response_payload_handler(token, user, request)
                response = Response(response_data)
                return response

            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

      -序列化类:JSONWebTokenSerializer
    	class JSONWebTokenSerializer(Serializer):
            def validate(self, attrs):
                credentials = {
                    'username': attrs.get('username'),
                    'password': attrs.get('password')
                }

                if all(credentials.values()):
                    # auth的校验用户名和密码是否正确
                    user = authenticate(**credentials)

                    if user:
                        # 通过用户获得payload:{}
                        payload = jwt_payload_handler(user)
                        return {
                            'token': jwt_encode_handler(payload),
                            'user': user
                        }
                    else:
                        # 根据用户名和密码查不到用户
                        raise serializers.ValidationError(msg)
                else:	
                    # 用户名和密码不传,传多了都不行
                    raise serializers.ValidationError(msg)
                    

# 认证
	-认证类;JSONWebTokenAuthentication
    class JSONWebTokenAuthentication(BaseJSONWebTokenAuthentication):
        def get_jwt_value(self, request):
            # get_authorization_header(request)根据请求头中HTTP_AUTHORIZATION,取出token
            # jwt adsfasdfasdfad
            # auth=['jwt','真正的token']
            auth = get_authorization_header(request).split()
            auth_header_prefix = api_settings.JWT_AUTH_HEADER_PREFIX.lower()
            if not auth:
                if api_settings.JWT_AUTH_COOKIE:
                    return request.COOKIES.get(api_settings.JWT_AUTH_COOKIE)
                return None
            if smart_text(auth[0].lower()) != auth_header_prefix:
                return None
            if len(auth) == 1:
                msg = _('Invalid Authorization header. No credentials provided.')
                raise exceptions.AuthenticationFailed(msg)
            elif len(auth) > 2:
                msg = _('Invalid Authorization header. Credentials string '
                        'should not contain spaces.')
                raise exceptions.AuthenticationFailed(msg)
            return auth[1]
        
   -父类中:BaseJSONWebTokenAuthentication---》authenticate
class BaseJSONWebTokenAuthentication(BaseAuthentication):
    def authenticate(self, request):
        # jwt_value前端传入的token
        jwt_value = self.get_jwt_value(request)
        # 前端没有传入token,return None,没有带token,认证类也能过,所有咱们才加权限类
        if jwt_value is None:
            return None
        try:
            payload = jwt_decode_handler(jwt_value) # 验证token,token合法,返回payload
        except jwt.ExpiredSignature:
            msg = _('Signature has expired.')
            raise exceptions.AuthenticationFailed(msg)
        except jwt.DecodeError:
            msg = _('Error decoding signature.')
            raise exceptions.AuthenticationFailed(msg)
        except jwt.InvalidTokenError:
            raise exceptions.AuthenticationFailed()

        user = self.authenticate_credentials(payload) # 通过payload得到当前登录用户

        return (user, jwt_value) # 后期的request.user就是当前登录用户
    
    
 # 它这个认证类:只要带了token,request.user就有只,如果没带token,不管了,继续往后走
posted @ 2022-10-17 08:55  |相得益张|  阅读(607)  评论(0编辑  收藏  举报