RBAC介绍

RBAC是一种认证规则 RBAC:Role-Based Access Control –>基于角色的访问控制

公司内部系统:crm,客户管理系统;oa系统,自动化运维项目

原理:权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便

Django的auth组件采用的规则及时RBAC

实现RBAC:

- user表:存用户信息
- Permission表:存权限:发工资、招人
- Role/group表:存角色:市场、销售、运营、开发
- 用户和角色,多对多的中间表
- 权限和角色,多得多的中间表
- 用户和权限,多对多的中间表

Django中auth表:

  • auth_group 角色表
  • auth_user 用户表
  • auth_permission 权限表
  • auth_user_groups 用户和角色多对多中间表
  • auth_group_permissions 角色和权限多对多中间表
  • auth_user_user_permissions 用户和权限多对多中间表

Django有后台管理admin,自带RBAC,有的公司基于admin做二次开发(xadmin,simple-ui)

有的公司自己基于前后端分离实现RBAC:https://github.com/liqianglog/django-vue-admin

前后端混合的后台前端模板 :X-admin:lay-ui+jq实现的纯静态页面(html,css,js),帮助我们快速开发后台管理系统

智慧大屏:https://gitee.com/kevin_chou/dataVIS.git

JWT

JWT介绍

jwt是什么:Json web token (JWT),一种前后端的认证方式

JWT的构成:头.荷载.签名


    头(header):认证方式,加密方式,公司名字...
        {
            \'typ\': \'JWT\',
            \'alg\': \'HS256\'
        }
    荷载(payload):用户信息,过期时间,签发时间...
        {
            "userid": "2",
            "name": "John Doe",
            "exp": 1214356
        }
    签名:将头和荷载通过某种方式加密得到的一串字符

签发和校验

签发:用户登录成功,构造token的头和荷载,使用设置好的加密方式对头和荷载进行加密,得到签名token,将三个部分进行拼接(使用base64编码)
校验:用户携带token,来到后端,把头和荷载再使用同样的加密方式加密,得到新的签名,比较新签名和旧签名是否一致,如果一致,说明该token可以信任,解析出当前用户,继续往后走
token例子:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

base64编码

### 编码
import base64
import json
dic={\'name\':\'lqz\',\'id\':1}
user_info_str=json.dumps(dic)
# res=base64.b64encode(bytes(user_info_str,encoding=\'utf-8\'))
res=base64.b64encode(user_info_str.encode(\'utf-8\'))
print(res) # eyJuYW1lIjogImxxeiIsICJpZCI6IDF9


###  解码
res=base64.b64decode(\'TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ=\'.encode(\'utf-8\'))
print(res)


### 注意:base64长度是4的倍数,如果不足,需要用 = 补齐

JWT快速使用

# 签发和验证
# 使用第三方:
	-djangorestframework-jwt:好久不维护,还能用
    -djangorestframework-simplejwt:最新的,https://django-rest-framework-simplejwt.readthedocs.io/en/latest/getting_started.html

签发

# 签发,只需要再路由中加入,向这个地址发送post请求,携带用户名密码,就可以签发token
# 内部使用的是,auth 的user表
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
    path(\'login/\',obtain_jwt_token)
]
# 只需要再前端向 /login/地址,发送post请求,携带用户名密码,就可以签发token

# 认证

认证

# 需要在视图类中配置上认证类和权限类两个
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated
class BookView(ViewSetMixin,ListAPIView):
    authentication_classes = [JSONWebTokenAuthentication,]
    permission_classes = [IsAuthenticated,]
    
    
### 前端访问,需要在请求头中加入,如果不携带,或者篡改了,就认证不通过
Authorization:jwt eyJ0eXAiOiJKV1QiLChbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyLCJ1c2VybmFtZSI6InJvb3QiLCJleHAiOjE2MjU3Mjk3MDAsImVtYWlsIjoiM0BxcS5jb20ifQ.V6X_4wdBvrrRSPOuUf8z5gENB1kJyGimxiLBEjbiQGY

自定制返回格式

# 自己写一个返回的函数,模板使用rest_framework_jwt.utils.jwt_response_payload_handler
def jwt_response_payload_handler(token, user=None, request=None):
    return {
        \'code\':100,
        \'msg\':\'登录成功!\',
        \'user\': user.username,
        \'token\': token,
    }


# 配置文件中
JWT_AUTH = {
    # token的过期时间
    \'JWT_EXPIRATION_DELTA\': datetime.timedelta(days=7),
    # 更改使用的返回函数
    \'JWT_RESPONSE_PAYLOAD_HANDLER\':
        \'app01.utils.jwt_response_payload_handler\',
}

djangorestframework-jwt模块obtain_jwt_token源码分析

# obtain_jwt_token-->ObtainJSONWebToken-->JSONWebTokenAPIView的post方法

def post(self, request, *args, **kwargs):
    serializer = self.get_serializer(data=request.data)

    if serializer.is_valid():
        user = serializer.object.get(\'user\') or request.user
        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)


# .is_valid()触发了validate(self, attrs)方法
# obtain_jwt_token-->ObtainJSONWebToken-->JSONWebTokenSerializer序列化类-->validate(self, attrs)钩子函数
 def validate(self, attrs):
        credentials = {
            self.username_field: attrs.get(self.username_field),
            \'password\': attrs.get(\'password\')
        }

        if all(credentials.values()):
            # 根据用户名密码去auth的user表校验,是否存在
            user = authenticate(**credentials)
            if user:
                if not user.is_active:
                    msg = _(\'User account is disabled.\')
                    raise serializers.ValidationError(msg)
                payload = jwt_payload_handler(user)
                # 生成payload
                return {
                    \'token\': jwt_encode_handler(payload),# 通过payload生成token
                    \'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)

版权声明:本文为zheng-sn原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/zheng-sn/p/15053871.html