drf从入门到精通---day10(drf-jwt源码执行流程,自定义用户表签发和认证,设置token过期时间,simpleui的使用,rbac权限控制,)

昨日回顾

# 1 接口文档的编写
	-1 word,md 编写----》存放位置:存放共享文件平台,git上
    -2 第三方的接口文档编写平台
    -3 公司自己开发,使用开源搭建  yapi
    -4 自动生成接口文档
    	-djagno+drf:swagger,coreapi
        -FastAPI:自带自动生成接口文档
        
        
        
   -接口文档应该有的东西
	-接口描述
    -请求地址
    -请求方式
    -请求编码格式
    -请求参数(get请求参数,post,put请求参数)
    	-参数类型
        -参数是否必填
        -参数解释
    -返回数据
    	-json格式示例
        -重点参数解释
    -错误码:写到全局


# 2 cookie,session,token发展历史
-会话保持
	-cookie:存在于客户端浏览器的键值对
	-session:存于服务端的键值对(可能存的位置:文件,内存,数据库。。。)会占用后端资源
	-token:三部分:头,荷载,签名
		-签发:登录
		-认证:携带着token过来进行认证,确认无误,才能调用需登录后才能访问的接口

        认证的代码可以写在的位置取决于你用的框架可能存在的位置:
        		-认证类
        		-中间件
        		-装饰器
        		-别的位置


# 3 jwt:json web token :前后端认证的机制,token的web形式认证机制
----------------------------------
# 4 base64
	-jwt
    -前后端交互:字符串---》base64编码
    -图片:使用base64编码
base64.b64encode(dic_str.encode('utf-8'))
# 字典先转json字符串,再转二进制后才能用base64编码

base64.b64decode('joYZgeFONFh7HgQ=')
----------------------------------
# 5 django+drf如何使用jwt
	-drf-jwt

----------------------------------
# 6 快速签发
	-配置一条路由----》帮咱们写了登录接口

----------------------------------
# 7 定制返回格式
	-写一个函数要定义3个行参  token,User=None,request=None
	返回什么,前端就看到什么
	-配置文件中配置

----------------------------------
# 8 jwt 的认证
	-局部:视图类上
    	-认证类  ---》JSONWebTokenAuthentication
    	-权限类:drf  IsAuthenticated
    -全局


    -携带token
    	-请求头中
        	Authorization:jwt sadsfasdfasdf.asdfasdf.asdfasdf

'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300)

----------------------------------
# jwt 配置问题
	-记住的  # token过期时间
    	-JWT_RESPONSE_PAYLOAD_HANDLER
        -'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300)
	# 一般过期时间设7天

    	-了解的
    	'JWT_AUTH_HEADER_PREFIX': 'JWT',  # 认证头前缀!这也是为什么
    	'JWT_SECRET_KEY': settings.SECRET_KEY,  # 密钥

image
.
这个密钥是一开始创项目的时候,自动随机生成的!
image
.
还可以从rest_framework_jwt文件里面的settings里面将'JWT_SECRET_KEY': settings.SECRET_KEY,这行话可以直接放到项目的配置文件里面去
image
.
.
.
.
.
.

今日内容

1 drf-jwt源码执行流程(了解,读懂就可以自己封装一个jwt了)

1.1 补充


#1 django 的auth  user表,密码是加密的,即便的同样的密码,密文都不一样
	-每次加密,都会随机生成一个盐
-------------------------------------
# 比如 auth表中的用户密码为
pbkdf2_sha256$260000$B9ZRmPFpWb3H4kdDDmgYA9$CM3Q/ZfYyXzxwvjZ+HOcdovaJS7681kDsW77hr5fo5o=

pbkdf2_sha256   加密方式
260000   固定数字
B9ZRmPFpWb3H4kdDDmgYA9   随机生成的盐

CM3Q/ZfYyXzxwvjZ+HOcdovaJS7681kDsW77hr5fo5o=
这个是用注册的密码和盐拼在一起然后用加密算法生成的字符串

当登录的时候,用户提交用户名与密码过来后,从数据库表里面拿出该用户的盐与登录的密码
合在一起,然后用加密算法再生成字符串,然后比较生成的字符串 与 数据库里面的该字符串
CM3Q/ZfYyXzxwvjZ+HOcdovaJS7681kDsW77hr5fo5o=  进行比较对了就确认用户密码输入正确

----------------------------------------

#2 自定义用户表,生成密码用密文
django 里面自带了一个函数make_password ,往函数括号里面传个明文,会自动生成一个密文

from django.contrib.auth.hashers import make_password

res = make_password('teng123')   # 就会自动加密了

要在项目启动起来,该代码才能正常执行
项目没启动起来的情况下, 用到django的东西得在测试环境,才能运行!!!

.
.
.
.

1.2 jwt如何自动完成token签发(自动登录)

# 登录接口,post请求,路由匹配成功,执行obtain_jwt_token-----
# obtain_jwt_token = ObtainJSONWebToken.as_view()
# -----最终执行的是ObtainJSONWebToken的post方法
	path('login/', obtain_jwt_token),


# ObtainJSONWebToken类继承了JSONWebTokenAPIView
class ObtainJSONWebToken(JSONWebTokenAPIView):
    serializer_class = JSONWebTokenSerializer

# JSONWebTokenAPIView类继承了APIView,
# JSONWebTokenAPIView里有post方法

    def post(self, request, *args, **kwargs):
    # 实例化得到序列化类的对象,就是JSONWebTokenSerializer(data=request.data)产生对象
        serializer = self.get_serializer(data=request.data)

        # 做校验:字段自己,局部钩子,全局钩子
        if serializer.is_valid():

            # user:获取全局钩子函数运行的返回结果里面的 当前登录用户
            user = serializer.object.get('user') or request.user
            # 同理获取签发的token
            token = serializer.object.get('token')

        # 构造返回格式,咱们可以自己定制,就是上节课讲的我们写在utils.py里面的函数!!
            response_data = jwt_response_payload_handler(token, user, request)
            response = Response(response_data)

            if api_settings.JWT_AUTH_COOKIE:
                expiration = (datetime.utcnow() +
                              api_settings.JWT_EXPIRATION_DELTA)
                response.set_cookie(api_settings.JWT_AUTH_COOKIE,
                                    token,
                                    expires=expiration,
                                    httponly=True)
       # 如果我们在jwt的配置文件里面把'JWT_AUTH_COOKIE'设置成True,就会走if里面的代码
         # 作用就是前后端混合也能用,走这里就会把token往cookie里面写
       # 我们现在前后端分离,后端正常是把token也放在字典里面用Response返回给前端,前端从响应体里面拿token

            #最终返回了咱们定制的返回格式
            return response

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

image
.
.
.
.
.

1.3 jwt如何自动完成token签发(自动登录) 如何得到user


# 如何得到user,如何签发的token----》在序列化类的全局钩子中得到的user和签发的token !!
# 也就是说在执行serializer.is_valid()的时候,就会执行全局钩子函数validate
# JSONWebTokenSerializer序列化类---全局钩子---validate

# if serializer.is_valid():就会执行JSONWebTokenSerializer里面的validate函数,为什么?
# 因为JSONWebTokenSerializer最终继承的是BaseSerializer所以走该类里面的is_valid函数
# 该类里面的is_valid函数函数里面走全局钩子validate函数
# 但是JSONWebTokenSerializer也有validate函数,所以就会运行JSONWebTokenSerializer
# 里面的validate函数


    def validate(self, attrs):
# attrs 就是前端传入,校验过后的数据--{"username":"lqz","password":"lqz1e2345"}

        credentials = {
            # self.username_field: attrs.get(self.username_field),
            'username':attrs.get('username')
            'password': attrs.get('password')
        }

        if all(credentials.values()):
            # 如果credentials字典里面的两个键对应的值都有值,就可以继续往下走

            # auth 模块,authenticate方法 可以传入用户名,密码
            # 如果用户存在,就返回当前登录的用户对象,如果不存就是None
            # 这行代码,这也是为什么jwt能自动完成登录确认的原因!!!
            user = authenticate(**credentials)

            if user:
                # 校验用户是否是活跃用户,如果禁用了,也不能登录成功
                if not user.is_active:
                    msg = _('User account is disabled.')
                    raise serializers.ValidationError(msg)

                # 重要---通过user得到荷载   {id,name,email,exp}
                payload = jwt_payload_handler(user)   # 重点代码

                return {
                    # 重点代码  jwt_encode_handler函数通过荷载就能得到token串
                    'token': jwt_encode_handler(payload),
                    'user': user }
            else:
                msg = _('Unable to log in with provided credentials.')
                raise serializers.ValidationError(msg)
        else:
            msg = _('Must include "{username_field}" and "password".')
            msg = msg.format(username_field=self.username_field)
            raise serializers.ValidationError(msg)

-----------------------------------------
-----------------------------------------
### 重点代码!!!!:
	1 利用django的authenticate模块,通过authenticate()方法,根据传过来的用户名与密码拿到当前登录用户对象user

	2 通过用户名与密码去数据库查询出对象 user = authenticate(**credentials)
	3 通过user对象得到荷载:payload = jwt_payload_handler(user)
	4 通过荷载签发token:jwt_encode_handler(payload)

-----------------------------------------
-----------------------------------------
## 了解:
	# 翻译函数,只要做了国际化,放的英文,会翻译成该国语言(配置文件配置的)
	from django.utils.translation import ugettext as _
	msg = _('Unable to log in with provided credentials.')

-----------------------------------------

image
.
image
image
.
通过user_obj对象生成payload
from rest_framework_jwt.utils import jwt_payload_handler
image
.
通过payload生成token串
from rest_framework_jwt.utils import jwt_encode_handler
image
.
.
.
.
.

1.4 jwt自带的认证类源码分析(JSONWebTokenAuthentication认证类)


# JSONWebTokenAuthentication---->父类BaseJSONWebTokenAuthentication----》
# authenticate方法

from rest_framework_jwt.authentication import JSONWebTokenAuthentication


    def authenticate(self, request):

        # 获取前端带在请求头中的token值  这个代码很重要
        jwt_value = self.get_jwt_value(request)


  # 如果没有携带token,就不校验了!!所以才要配合drf的登录的权限类,来确认是否携带token
        if jwt_value is None:
            return None

        try:
            payload = jwt_decode_handler(jwt_value)  # 重点代码
            # jwt_value就是token
            # 通过token,得到荷载,得到荷载的过程中可能会出错!!!
            # 出错的原因:用户篡改token串,token过期了,未知错误

        except jwt.ExpiredSignature:
            msg = _('Signature has expired.')  # 过期了
            raise exceptions.AuthenticationFailed(msg)
        except jwt.DecodeError:
            msg = _('Error decoding signature.')  # token串有问题导致解出来的签名不一样
            raise exceptions.AuthenticationFailed(msg)
        except jwt.InvalidTokenError:
            raise exceptions.AuthenticationFailed()

        # 如果能顺利解开,没有被异常捕获,说明token是可以信任的
        # payload就可以使用,通过payload得到当前登录用户对象
        user = self.authenticate_credentials(payload)

        # 返回当前登录用户,token
        return (user, jwt_value)

----------------------------
# 获取前端带在请求头中的token 值
# jwt_value = self.get_jwt_value(request)
# get_jwt_value函数在JSONWebTokenAuthentication类里面

    def get_jwt_value(self, request):
        # get_authorization_header函数作用获取前端请求头中传入的 jwt token串
        # 按空格切割再解压赋值的列表 auth=['jwt','token串']
        auth = get_authorization_header(request).split()
        # 获取jwt的配置文件里面的认证头前缀转小写,实际上就是'jwt'
        auth_header_prefix = api_settings.JWT_AUTH_HEADER_PREFIX.lower()

        if not auth:
            # 请求头中如果没带,去cookie中取
            if api_settings.JWT_AUTH_COOKIE:
                return request.COOKIES.get(api_settings.JWT_AUTH_COOKIE)
            return None

        # 如果前端传的不是jwt,直接返回空!!!
        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]  # 最终返回token值

-------------------------------------------
-------------------------------------------
jwt认证类代码总结:
# 当给接口函数配置了jwt自带的JSONWebTokenAuthentication认证类后,
# 如果不是 jwt空格token串 或者jwt空格token串里面jwt三个字母写错 ,都不会校验,
# 所以一定配合权限类使用permission_classes = [IsAuthenticated]
# 所以如果不带这个权限类进行限制,用户不带token就能直接继续运行视图类的相关方法的。
----------------------
# JSONWebTokenAuthentication  这个是jwt自带的认证类
# 该类里面有get_jwt_value函数,该类的父类里面有authenticate方法又调用get_jwt_value
# 最后的返回值就是get_jwt_value里面就是按Authorization键拿到jwt空格token串,
# 然后再split按空格切开,才拿到token串

# 所以要是用该认证类在请求头里面携带的token所对应的键就一定要是Authorization,值一定要先jwt空格再接token串的原因!!!

.
要对视图类的接口函数配jwt自带的登录认证类,有一个前提,
用户表是继承auth表的,如果自己写的用户表的时候,用不了jwt自带的登录认证类
原因是,用playload解析出user对象的时候,解析不出来,只有继承或用了auth表,才能解析出来
所以
image
image
.
.
这也是为什么没继承auth表,自己写的用户表,加了jwt自带的登录认证类后,虽然请求头里面
携带了jwt token串,显示无效签名的原因!!!
解决办法,自己重写认证类,别用jwt自带的登录认证类了!!!
image
.
.
.
.

2 自定义用户表进行签发和认证( 重要!!! )

也就是不用jwt自带的快速签发功能,自己写登录接口函数,不用jwt自带的认证类,自己写认证类
.
.

2.1 自定义用户表签发(登录接口)

代码示范

视图层
from rest_framework.viewsets import ViewSet
from rest_framework.decorators import action
from app01.models import Userinfo
from rest_framework.response import Response

from rest_framework_jwt.settings import api_settings  # 导入jwt的配置文件

# JSONWebTokenSerializer类的上面复制过来的
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
from django.contrib import auth


class UserView(ViewSet):
    @action(methods=['POST'], detail=False)
    def login(self, request, *args, **kwargs):
        username = request.data.get('username')
        password = request.data.get('password')
        user_obj = Userinfo.objects.filter(username=username, password=password).first()
       # user_obj = user_obj = auth.authenticate(request, username=username, password=password)
 # 注意如果用的或继承的auth_user表,注册在里面的密码是被加过密的,所以直接用密码的明文
 # 去表里面查是查不出用户对象的,authenticate方法有自动加密并查询的功能

        if user_obj:
            # 自己签发token,通过user_obj 得到payload
            payload = jwt_payload_handler(user_obj)
            # 自己通过payload 得到token
            token = jwt_encode_handler(payload)
            return Response({'code': 100, 'msg': '登录成功', 'token': token})
        else:
            return Response({'code': 101, 'msg': '用户名或密码错误'})

# 就是自己写登录接口函数,自己用前端的用户名与密码去数据库了查出对象,
# 确认密码账号没有问题,并拿到对象,自己通过对象的到荷载,通过荷载签发token,最后自己返回给前端
# 要是用jwt的快速签发功能,jwt封装的代码帮你全干了!!

.
.
.
.

2.2 自定义用户表认证

代码示范

视图层
from app01.authentication import JsonWebTokenAuthentication

class TestView(ViewSet):
    authentication_classes = [JsonWebTokenAuthentication]

    @action(methods=['GET'], detail=False)
    def test(self, request):
        return Response('ok')

------------------------------------
# 这是我们自己写的自定义的认证类,就是抄的的jwt自带的认证类JSONWebTokenAuthentication

# from rest_framework_jwt.authentication import JSONWebTokenAuthentication

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
import jwt
from rest_framework_jwt.utils import jwt_decode_handler

from app01.models import Userinfo


#
class JsonWebTokenAuthentication(BaseAuthentication):
    def authenticate(self, request):
        # 取出token
        token = request.META.get('HTTP_TOKEN')

        if token:
            try:
                payload = jwt_decode_handler(token)  # 重点代码 用token获取荷载

                user_obj = Userinfo.objects.get(pk=payload.get('user_id'))
  # 得到当前用户对象,get是filter与first的结合,但是如果拿不到直接报错,说明荷载有问题

            # 只要访问一次登录接口,就会去Userinfo表中查一次用户---优化操作
                # user_obj = Userinfo(id=payload.get('user_id'),username=payload.get('username'))
                # 或者user_obj={'id':payload.get('user_id')}
                return token,user_obj

            except jwt.ExpiredSignature:
                raise AuthenticationFailed('token过期')

            except jwt.DecodeError:
                raise AuthenticationFailed('token认证失败')

            except jwt.InvalidTokenError:
                raise AuthenticationFailed('token无效')
            except Exception as e:
                raise AuthenticationFailed('未知错误')

        raise AuthenticationFailed('token没有传,认证失败')


# 我们自己写了认证类,也写了authenticate方法,这样给接口函数配上后,
# 前端在请求头里面放token串时,键就是字符串token,值就是token串,不用再加jwt空格了!!
# 因为我们没有像jwt源码那么烦,我们直接按token取的,也没按空格切割取索引1这些操作,没有花里胡哨的操作,所以token串前不加jwt空格了
-------------------------------------
# 配置
import datetime

JWT_AUTH = {
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),  # token过期时间
}
--------------------------------------

.
.
.

以下所有代码在,D:\pythonProject\drf_day09

.
.

3 simpleui的使用


# 之前公司里,做项目,要使用权限,要快速搭建后台管理
# 使用djagno的admin直接搭建,但django的admin界面不好看
---------------------------------------------

# 就有了第三方模块的美化:
	-xadmin:作者弃坑了,基于bootstrap+jq写的

	-simpleui:基于vue写的,界面更好看

--------------------------------------------

# 现在阶段,一般前后端分离比较多:后台一般是django+前端一般是vue
	-带权限的前后端分离的快速开发框架
	-django-vue-admin  # 类似于django-vue-admin的框架 是很多公司内部系统的基础框架
	-自己写

.
.
.

3.1 使用步骤


# simpleui官方文档,点击教程&指南  查看如何使用
https://simpleui.72wo.com/docs/simpleui/

-----------------------------------------------
# 1 安装
pip3.8 install django-simpleui

# 2 在app中注册一下!! 放在注册的app的列表里面的最上面
INSTALLED_APPS = [
    'simpleui',
                 ]
只要下载了模块,注册了,立马django的后台就变了
----------------------------------------

image
.
image
.
.
.
.
.

# 3 内部app,图书管理系统某个链接要展示的字段 要在项目的admin.py 中注册一下

# 自定义按钮
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
    list_display = ('nid', 'name', 'price', 'publish_date', 'publish')  # 多对多字段不能往括号里写

    # Book表里面增加自定义按钮
    actions = ['custom_button']
    def custom_button(self, request, queryset):
        # queryset 就是选的对象
        print(queryset)  # 点击该按钮就会触发函数代码的执行


    custom_button.confirm = '你是否执意要点击这个按钮?'
    # 点击按钮就会触发一个确认的弹窗,并显示对应的文本

    custom_button.short_description = '测试按钮'  # 按钮的名字

    # icon,参考element-ui icon与https://fontawesome.com
    custom_button.icon = 'fas fa-audio-description'  # 按钮带个小图标
    # 指定element-ui的按钮类型,参考https://element.eleme.cn/#/zh-CN/component/button
    custom_button.type = 'danger'

    # 给按钮里面字体追加自定义的颜色
    custom_button.style = 'color:black;'

想要展示表里面的多个字段
image
image
image
.
.
其他表同理也这样改改,英文就变成中文了,
image
这样快速的就有了一个后台的每一个表就有了增删查改功能了
.
.
actions里面的按钮要配合函数使用
queryset 就是选的对象,点击该按钮就会触发函数的执行
image
image
.
.
.
.
.

# 4 调整左侧导航栏    比如在左侧菜单栏再添加一个按钮怎么办?
------------------------
	1. menu_display对应menus字典里面的name键对应的值

	2. 如果是项目的app,就在menus字典里面注册一下app的名字
	3. 菜单可以多级,一般咱们内部app,都是两级,比如图书管理是一级,下面的表是二级

	4. 可以增加除咱们app外的其它链接---》如果是外部链接,直接写地址,
	5. 如果是内部链接,跟之前前后端混合项目一样的写法,直接写路由

--------------------
粘贴到项目的配置文件里面

import time
SIMPLEUI_CONFIG = {
    'system_keep': False,

    # 一级菜单
    'menu_display': ['图书管理', '权限认证', '张红测试'],
    # 开启排序和过滤功能, 不填此字段为默认排序和全部显示,
    # 空列表[] 为全部不显示.

    'dynamic': True,
    # 设置是否开启动态菜单, 默认为False. 如果开启, 则会在每次用户登陆时动态展示菜单内容

    'menus': [
         {  # 第1个按钮
            'name': '图书管理',
            'app': 'app01',     # 注册一下项目名!!!  很重要!!!
            'icon': 'fas fa-code',    # fas fa-code对应的图标是 </>

            # 二级菜单
            'models': [
                {
                    'name': '图书',
                    'icon': 'fa fa-user',   # fa fa-user对应的图标是个小人头像图标
                    'url': 'app01/book/'},
                {
                    'name': '出版社',
                    'icon': 'fa fa-user',
                    'url': 'app01/publisssh/'},
                {
                    'name': '作者',
                    'icon': 'fa fa-user',
                    'url': 'app01/author/'},
                {
                    'name': '作者详情',
                    'icon': 'fa fa-user',
                    'url': 'app01/authordetail/'},
                     ]        },


        {   # 第2个按钮
            '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/'},
                        ]
        },

        {   # 第3个按钮
            'name': '张红测试',
            'icon': 'fa fa-file',  # 文本的图标


            'models': [

                 # 二级菜单
                {   'name': 'Baidu',
                    'icon': 'far fa-surprise',

                    # 第三级菜单
                    'models': [
                        {   'name': '爱奇艺',
                             'icon': 'fa-solid fa-bug-slash',
                            'url': 'https://www.iqiyi.com/dianshiju/'
                        },
                        {   'name': '百度问答',
                            'icon': 'fa-solid fa-filter',
                            'url': 'https://zhidao.baidu.com/'
                        }
                              ]
                },

                # 二级菜单
               {   'name': '大屏展示',
                    'url': '/show/',
                    'icon': 'fab fa-github'}
                    ]  # 'models'对应的列表结尾

        }  # 'menus'对应的列表里面的最后一个字典结尾

    ]  # 'menus'对应的列表结尾
}  # SIMPLEUI_CONFIG 字典的结尾


# 图标怎么改,https://fontawesome.com/icons/bug-slash?s=solid 网站上去找
# 看到喜欢的图标,左键点击,进入后,class="样式类"  去复制样式类  有的有用,有的没用

----------------------
# 第四级就不支持了,element只支持了3级菜单!!!
# 注意url对应的路由是你自己写的,但是你只要用了simpleui的后台管理
# 后台管理会自动帮你生成路由项目名 admin/ app01/authordetail/ 这种项目加表名组合的路由
# 所以你写的路由要和自动生成的路由对应上,点对应的图标按钮才会跳到对应的表页面上去!!!

# 如果你想要一个按钮有一个不存在的路由,那么你要先去路由层注册一下
# 或者url可以对应一个存在的外部网页链接

模型表里面表建好,注册一下,再重新打开后台就变了
image
.
改左边项目的名字将app01改成中文
image
.
.
url对应的路由虽然是你自己写的,
但是一定要是已经存在的路由,你只要在django的项目的admin.py里面注册了模型表的表名,
并在settings里面注册了simpleui,simpleui会自动帮你生成路由这种
admin/ app01/authordetail/ 这种项目名加表名组合的路由
所以你写的路由要和自动生成的路由对应上,点对应的图标按钮才会跳到对应的表页面上去!!!
image
image
.
.
.
当想要写一些页面,这些页面又和表没有必然联系的时候,url对应的就要是我们项目中已经注册的路由了
image
image
image
image
要先退出一下,再登录再点大屏展示按钮,就会显示后端的视图函数render的html页面了
image
.
.
.
.


# 5.1  后台里面,将字段名字改成中文
	-新增,查看修改展示中文,在表模型的字段上加:verbose_name='图书名字' 与
	 help_text='这里填图书名'      来控制中文的显示与提示


# 5.2  后台里面,将app名字改成中文
	-app名字中文:apps.py---加个verbose_name = '图书管理系统'

---------------------------------------
---------------------------------------

image
.
.
.

# 6 其它配置项

SIMPLEUI_LOGIN_PARTICLES = False  # 关闭登录页面动态效果

	# 改登录页面的logo   原来的django图标就被替换掉了
SIMPLEUI_LOGO = 'https://avatars2.githubusercontent.com/u/13655483?s=60&v=4'


SIMPLEUI_HOME_INFO = False  # 隐藏首页右上角的服务信息
SIMPLEUI_HOME_QUICK = False  # 隐藏首页的快捷操作图标内容
SIMPLEUI_HOME_ACTION = False  # 隐藏首页的最近动作
---------------------------------------

# SIMPLEUI_HOME_PAGE = 'https://https://www.cnblogs.com/'  不怎么好用 改首页配置
# SIMPLEUI_HOME_TITLE = '博客园首页'  不怎么好用 改首页标题
# SIMPLEUI_HOME_ICON = 'fa fa-user'  不怎么好用 改首页图标3个不太会用,要琢磨一下,怎么用

隐藏右上角的服务信息,配置文件里面再加一行代码
SIMPLEUI_HOME_INFO = False
image
image
.
.
SIMPLEUI_HOME_QUICK = False # 隐藏首页的快捷操作图标内容
SIMPLEUI_HOME_ACTION = False # 隐藏首页的最近动作
image
image
.
.
.
.
.
.
.

3.2 大屏展示

# 监控大屏展示   到gitee上面 https://gitee.com/
	搜索展示大屏

--------------------------------
	适用于前后端混合项目,js,css,图片对应好,就可以了

	就是别人写的很好看的前端,我们抄过来,用模板语法做个替换,就可以了

----------------------------
----------------------------
注意一点,路由匹配的时候,如果路由的前面没有斜杠就会以当前所在的路由为基础往后匹配
如果路由的前面加了斜杠,就会从端口号后面开始匹配

打个比方
假如一个图片的路径是img/second_title.png  当前的页面的路由是index/
在该页面加载加载该图片的时候,图片的路径变成index/img/second_title.png

假如图片的路径是/img/second_title.png  当前的页面的路由是index/
在该页面加载加载该图片的时候,图片的路径还是/img/second_title.png
---------------------------------

image
.
下载下来后,用pycharm打开
image
image
.
.
找到好看的,复制文件,粘贴到我们自己的项目里面的static静态文件夹内
settings里面静态文件的路径
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
image
.
再把index.html页面复制到我们项目的templete里面去
image
.
然后urls.py 里面配个路由,写个视图函数,专门就render到index.html页面,
这样就能访问到该html页面了,但是没样式
image
.
因为里面的文件路径没改了,要改一下
href=" 改成 href="static/ src=" 改成 src="static/
json/ 改成 /static/json/ img/改成 /static/img/
image
image
.
就成这样了,当然页面里面的数据都不是写死了,后端都是可以传到前端替换的
image
.
.
最后想要把大屏监控的按钮,放到左边侧边栏,搞定了!!!
image
image
.
.
.
.
.
.
.
.

4 权限控制(acl,rbac)

# python的应用场合:公司内部项目要快速开发成形,而不讲究太高的执行效率的情况下!!!


# 公司内部项目 一般是基于角色的访问控制 rbac
rbac:是基于角色的访问控制(Role-Based Access Control )在 RBAC  中,
权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。
这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,
而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便
-----------------------

用户表:用户和角色多对多关系,一个用户可能有多个角色,一个角色也可能会被赋予多个用户!!!
-----------------------

角色表: 一个角色可能有多个权限----》
		-开发角色:拉取代码,上传代码
		-财务角色:开工资,招人,开除人
-----------------------

权限表:角色和权限也是是多对多,
一个角色可以有多个权限,一个权限也可以赋予给多个角色!!!

		-拉取代码
		-上传代码
		-开工资
		-招人
		-开除人

补充: 权限表里面的权限不是直接和用户有关系的,而是把权限赋给角色
基于角色的访问控制的核心是角色,角色有什么权限,用户只要属于该角色就能拥有什么权限

换句话说就是把权限赋予角色,把角色赋予用户,从而间接的控制用户有什么权限了

-----------------------

# 通过5张表完成rbac控制:用户表,角色表,权限表, 用户角色中间表, 角色权限中间表

一个用户登录了,想要知道他的权限,首先要拿到他所有角色,然后根据这些角色拿到所拥有的权限

-----------------------
-----------------------
# 如果某个人,属于财务角色,但只想要拉取代码权限,不要上传代码权限,怎么办?
# 肯定不可能把 开发角色 赋予给他,开发角色一给他肯定就有上传代码的权限了!!!


# 通过6张表来实现权限控制
	用户表,
	角色表,
	权限表,
	用户角色中间表,
	角色权限中间表
	用户和权限中间表  # 直接把权限授给用户,也是多对多


# 一个用户可以有多个权限,一个权限也可以授给多个用户!!!
# 这样的话,用户登录,查看他的权限,先查他的角色,把角色有的权限拿出来,
# 再到用户和权限中间表,把与用户直接关联的权限拿出来,再合起来,就是该用户的所有权限了

# diango的admin后台管理就是基于这6张表来实现的权限认证!!!
# 这就是为什么公司的内部管理系统想快速搭建,就用django的admin,在基础上做二次开发
# 原因就是权限不用写了,只需要写功能就行了

-------------------------------------------------
-------------------------------------------------
-------------------------------------------------

# 互联网项目 一般是基于访问列表的控制 acl ,比较简单
acl:Access Control List 访问控制列表,权限放在列表中,
只要列表中有,就有该权限,列表中没有,就没有该权限!!
所以用户一登录,该用户的权限表就已经加载出来了!!!

    -权限:权限表----》 发视频,评论,开直播
    -用户表:用户和权限是一对多

    张三:[发视频,]
    李四:[发视频,评论,开直播]

-------------------------------------------------

.
.

4.1 基于django-admin实现权限控制的操作

# 演示了 django-admin 的权限控制
	由超级管理员来操作权限的分配,首先给用户分配组(角色),
	其次如果该用户需要一些特殊的权限,没有组满足,就可以单独给用户授予权限!!!

	-授予用户某个组
	-单独单独给用户授予权限

---------------------------
---------------------------
# django的admin就是基于auth写的
# django的auth--6张表

	auth_user          # 用户表
	auth_group         # 角色表,组表
	auth_permission       # 权限表
-----------
	auth_user_groups    # 用户和角色中间表
	auth_group_permissions  # 角色和权限中间表
-------------
	auth_user_user_permissions  # 用户和权限中间表

---------------------------
---------------------------

# java:若依
# go :gin-vue-admin
# python :django-vue-admin

先添加组
image
image
.
由于我们创的用户都是超级管理员,超级管理员是有所有权限的
所以要先把用户的超级管理员身份去掉,一去掉保存,数据库user表里超级管理员字段数据也对应改了
然后再给该用户分配组(就是角色) 这样该用户就只有该组的权限了!!!
image
image
.
.
可以看到,给用户分配了,只能看书与出版社组后,该用户就只能看了,不能增删改了!!!
而且左边侧边栏,只有两个权限对应的按钮了,其他按钮直接没了!!!
image
image
.
.
.
.

django后台英文转中文


django的一个中间件,加了,后台的英文就变中文了
'django.middleware.locale.LocaleMiddleware',

或者
django是支持修改语言环境的,改一下LANGUAGE_CODE = 'zh-hans',
整个django的系统语言环境全部变成汉文了

.
.
.

补充


#3  用户表的密码忘了怎么办
	-新增一个用户,把它的密码复制过去

# 4 双token认证

.
.
.
.
.
.
.

作业

1 整理 jwt 签发,认证流程
2 自定义用户表,签发,认证
3 自定义用户表,使用make_password保存密码

4 simpleui  写个图书管理系统
5 演示一下admin  的rbac

----------------------
6 研究 python casbin  支持acl rbac,abac。。。。权限控制
7 双token认证
posted @   tengyifan  阅读(114)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示