程序员的资源宝库

网站首页 > gitee 正文

基于自定义表编写认证类、django-jwt源码分析、权限介绍

sanyeah 2024-03-29 17:41:17 gitee 6 ℃ 0 评论

一、基于自定义表编写认证类

认证类:

auth.py:

# 写一个类继承BaseAuthentication,重写authenticate方法
from rest_framework.authentication import BaseAuthentication
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.exceptions import AuthenticationFailed
from rest_framework_jwt.settings import api_settings
import jwt
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
jwt_get_username_from_payload_handler = api_settings.JWT_PAYLOAD_GET_USERNAME_HANDLER
from .models import User

class JwtAuthentication(BaseAuthentication):
    # 重写authenticate方法
    def authenticate(self, request):
        # 获取前端传入的token进行验证,从请求头中获取token
        token = request.META.get('HTTP_TOKEN')
        # django——jwt 提供了校验token的方法,从这个JSONWebTokenAuthentication这个中找
        try:
            # jwt提供的方法,进行token的校验
            payload = jwt_decode_handler(token)  # 传入token进行校验,校验通过返回payload,校验失败抛异常
            # 通过payload 得到当前用户
            # 认证类,配好后,只要有认证的,都会走这里---》每次走这里都会查询一次数据库
            # 做个优化?
            # 1 自己根据payload数据,创建一个用户,有的参数没传,会使用默认值,跟我真实用户还是有区别的
            # user=User(id=payload.get('user_id'),username=payload.get('username'))
            # 2 直接返回用户id,后续 的request.user 都是用户id,如果真正要用的时候,再查
            user = User.objects.get(pk=payload.get('user_id'))
        except jwt.ExpiredSignature:
            # msg = _('Signature has expired.') # _是个函数的别名,这个函数是翻译函数,只要做了国际化,它就是中文
            msg = '签名过期'
            raise AuthenticationFailed(msg)
        except jwt.DecodeError:
            msg = 'token错误'
            raise AuthenticationFailed(msg)
        except jwt.InvalidTokenError:
            msg = 'token不合法'
            raise AuthenticationFailed(msg)
        except Exception:
            raise AuthenticationFailed('未知错误,请联系系统管理员')
        return (user, token)  # 后续的request.user 都是用户id,

 登录接口:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework_jwt.settings import api_settings  # drf的配置文件# from rest_framework_jwt.utils import jwt_payload_handler
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
# rest_framework_jwt.utils.jwt_encode_handler
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
from .models import User

# 自定义签发表签发
class UserView(APIView):
    def post(self, request):
        # 拿到前端提交的用户名、密码去表里查询
        username = request.data.get('username')
        password = request.data.get('password')
        user = User.objects.filter(username=username, password=password).first()
        if user:
            # 查询到了,说明用户名、密码正确,进行token签发
            # 通过user生成payload,jwt中有提供一个方法:
            payload = jwt_payload_handler(user)
            # jwt提供的方法:通过payload生成token
            token = jwt_encode_handler(payload)
            return Response({'code': 100, 'msg': '登录成功', 'token': token, 'username': user.username})
        else:
            return Response({'code': 101, 'msg': '用户名或者密码错误'})

路由:

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/',UserView.as_view()), # 自定义表签发路由
    path('test/', TestView.as_view()), #自定义表认证的测试接口路由
]

视图类:

# 测试接口
from rest_framwork.views import APIView
from .auth import JwtAuthentication
# 测试接口
class TestView(APIView):
    # 登录之后才能访问
    authentication_classes = [JwtAuthentication]
    def get(self,request):
        print(request.user) # User object (1)
        return Response({'code':100,'msg':'测试成功'})

postman测试结果:

 

二、 django-jwt源码分析

签发源码分析:

1. 入口:obtain_jwt_token 

  -from rest_framework_jwt.views import obtain_jwt_token

2. obtain_jwt_token的本质:ObtainJSONWebToken.as_view()

3. 看ObtainJSONWebToken视图类

  - 前端POST请求,提交了用户名和密码,就能签发token

  - 去 ObtainJSONWebToken中找post方法

4. 去父类JSONWebTokenAPIView中找post方法,

 5. 校验用户名密码和生成token,写在了序列化类:JSONWebTokenSerializer的全局钩子validate中:

 

注:字典.values():会拿出字典中所有的值

 

总结:

  - 前端携带用户名、密码到后端,执行后端的post方法,后端生成一个序列化类的对象

  - serializer.is_valid(),进行数据校验,走了全局钩子validate

  - 全局钩子中通过用户名和密码获取用户,如果获取不到,就抛异常

  - 获取到之后签发token

  - 签发完后返回,在视图类中,取出来,返回给前端

补充:

认证源码分析:

1. 从哪里看----》认证类:JSONWebTokenAuthentication

2. JSONWebTokenAuthentication:

 从父类BaseJSONWebTokenAuthentication类中找到了authenticate方法:

 三、权限介绍

所有项目都会有权限控制

1. ACL(访问控制列表)

  ACL是访问控制列表(Access Control List),针对互联网用户,多半是这个

  在ACL中,将用户与权限对接(多对多):一个用户可以有多个权限,一个权限可以被多个用户拥有

   比如:张三:[发视频,点赞,评论]

      李四:[看视频]

2. RBAC(基于角色的访问控制)

  RBAC 是基于角色的访问控制(Role-Based Access Control ):公司内部项目

  在 RBAC 中,将权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。django的 admin+auth 就是使用了这套认证机制。

python写公司内部项目比较多,使用rbac控制居多

如何设计:

  -用户表---》一堆用户:张三,李四
  -角色表(group组)---》用户的角色:后勤部,开发部,总裁办。。。
  -权限表-----》放了一堆权限:发电脑,提交代码,删除代码,发工资
  -用户和角色多对多:一个用户属于多个角色,一个角色属于多个用户
  -角色 和权限多对多:一个角色有多个权限,一个权限属于多个角色
  --------rabc----通过5张表可以实现
  -django为了更细粒度划分---》多了一张表,用户和权限多对多

演示django的RABC权限控制:

 先创建一个用户,在添加组,然后在给对应的用户选择相对应的组(角色表):

 

 

3. ABAC(基于属性的访问控制)

  ABAC是基于属性的访问控制(Atrribute-Based Access Control),又称为PBAC(Policy-Based Access Control,基于策略的访问控制),CBAC(Claims-Based Access Control,基于声明的访问控制)。

  传统的ACL、RBAC的架构是{subject,action,object},而ABAC的架构是{subject,action,object,contextual}且为他们添加了parameter(参数)。

  subject属性:比如用户的年龄、部门、角色、威望、积分等主题属性

  action属性:比如查看、读取、编辑、删除等行为属性

  object属性:比如银行账户、文章、评论等对象或资源属性

  contextual属性:比如时段、IP位置、天气等环境属性

四、simpleui的使用

公司内部,做公司内的项目需要使用这套权限控制

方案一:使用django-admin写

有的公司,不怎么写前端,直接使用django的admin,快速写出一套具有权限管理的系统

django-admin的界面不好看:第三方美化---》simpleui

方案二:自己写,前端使用vue,后端使用django,做公司内部的项目

  - 第三方开源的权限控制 项目

    - python界:django-vue-admin 

    - java界:若依

    - go界:gin-vue-admin

 使用:

1. 安装:pip install django-simpleui

2. 在配置文件中的INSTALL_APPS=['simpleui']

3. 然后再登入后台管理:admin 

  - 登录页面:

 

 在apps.py中修改:

 

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表