草庐IT

drf 认证组件、权限组件、频率组件

李李大冒险 2023-03-28 原文

认证组件

访问某个接口 需要登陆后才能访问 

#第一步 写一个登录功能 用户表
	User表
    UserToken表 :存储用户登录状态 【这个表可以没有 如果没有 把字段直接卸载User表上也可以】

登录接口

model.py

class Books(models.Model):
    name = models.CharField(max_length=32)
    price = models.CharField(max_length=32)
    publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE)
    authors = models.ManyToManyField(to='Authors')

    def publish_dict(self):
        return {'name':self.publish.name,'addr':self.publish.addr}

    def author_list(self):
        l = []
        for author in self.authors.all():
            l.append({'name':author.name,'phone':author.phone})
        return l

class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)

class Authors(models.Model):
    name = models.CharField(max_length=32)
    phone = models.CharField(max_length=32)

class User(models.Model):
    username = models.CharField(max_length=32)
    password = models.IntegerField()

class UserToken(models.Model):
    token = models.CharField(max_length=32)
    user = models.OneToOneField(to='User',on_delete=models.CASCADE,null=True)

url.py

router = SimpleRouter()
router.register('user',views.UserView,'user')
urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/', include(router.urls))
]

views.py

import uuid
from django.shortcuts import render
from .models import User, UserToken
from rest_framework.viewsets import ModelViewSet,ViewSet
from rest_framework.decorators import action
from rest_framework.response import Response


# Create your views here.

class UserView(ViewSet):
    @action(methods=['POST'], detail=False)
    def login(self, request):
        username = request.data.get('username')
        password = request.data.get('password')
        user = User.objects.filter(username=username, password=password).first()
        if user:
            token = str(uuid.uuid4())
           #用户登陆成功随机生成一个用不重复的字符串 
        	#在Usertoken表中存储一下 :1 从来没有登陆过 插入一条 2登陆过 修改记录
        UserToken.objects.update_or_create(user=user, defaults={'token': token})
            #如果有就修改 没有就新增 
            #kwargs 传入的东西查找 能找到 使用defaults的更新 否则新增一条
            return Response({'code': 100, 'msg': '登陆成功', 'token': token})
        else:
            return Response({'code': 101, 'msg': '用户名或密码错误'})
    
'''
以后 有的接口组要登录后才能访问 有的接口不登陆就能访问(查询所有不需要登录就能访问 查询单个 需要登陆才能访问)
	登录认证的限制
	
写登录接口 返回token 以后只要带着token过来 就是登陆了 不带就是没有登陆
'''

认证组件使用

# 查询所有不需要登录就能访问
# 查询单个,需要登录才能访问
# 在查询单个个视图类中写authentication_classes=[]

1.写一个认证类 需要继承BaseAuthentication

from rest_framework.authentication import BaseAuthentication

2.通过看源码分析 必须重写authenticate方法 在该方法中实现登录认证

3.如果认证成功 返回两个值【登录用户和token或None】

4.认证不通过 抛异常

from rest_framework.exceptions import AuthenticationFailed

5.局部使用和全局使用

局部:只在某视图类中使用【当前视图类管理的所有接口均使用过】

class BookView(ViewSetMixin,RetrieveAPIView):
    queryset = Books.objects.all()
    serializer_class = BooksSerializers
    authentication_classes = [LoginAuth]
    '''登录以后才能查询单个书信息'''

全局:全部接口都生效(登录接口不需要)

REST_FRAMEWORK={
'DEFAULT_AUTHENTICATION_CLASSES': ['app01.authentication.LoginAuth']
}
'''
所有接口都需要认证 登陆不能验证 局部禁用
'''

局部禁用:

class UserView(ViewSet):
    authentication_classes = [] 

view.py

#查所有
class BooksView(ViewSetMixin,ListAPIView):
    queryset = Books.objects.all()
    serializer_class = BooksSerializers

#查单个
class BookView(ViewSetMixin,RetrieveAPIView):
    queryset = Books.objects.all()
    serializer_class = BooksSerializers
    authentication_classes = [LoginAuth] #需要写一个认证类

authentication.py 认证类代码

#自己写的认证类 需要继承某个类
from .models import UserToken
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed

class LoginAuth(BaseAuthentication):
    def authenticate(self,request):
        #在这里实现用户的验证 如果是登录的继续走 不是就抛异常
        #请求中是否携带token判断是否登录 地址栏中 request是新的
        token = request.query_params.get('token',None)
        if token: #前端传入token 去表中查 如果查到了登录了返回两个值 固定的 1.当前登录用户 2.token
            user_token=UserToken.objects.filter(token=token).first()
            if user_token:
                return user_token.user,token
            else:
                raise AuthenticationFailed('token认证失败')#没登陆就抛异常
        else:
            raise AuthenticationFailed('token没传')

权限组件

即便登陆成功 有些接口 还是不能访问 因为没有权限

登陆后 有的接口有访问权限 有的没有

查询单个和查询所有 都要登录才能访问 -- 全局认证
	查询单个需要超级管理员
    查询所有需要登陆的用户
    
权限是一个字段 在User表中加入user_type
字段

权限的使用

1.写一个权限类 继承BasePermission

from rest_framework.permissions import BasePermission

2.重写has_permission方法 在该方法实现权限认证 在这方法中request.user就是当前登录用户

3.如果有权限 返回True

4.如果没有权限 返回False 定制返回中文 self.message = '中文'

5.局部使用和全局使用

局部:只在某个视图类中使用【当前视图类管理的所有接口都使用

class BookView(ViewSetMixin,RetrieveAPIView):
    queryset = Books.objects.all()
    serializer_class = BooksSerializers
    authentication_classes = [LoginAuth] #需要写一个认证类
    permission_classes = [CommonPermission] #认证和权限都可以加多个 多层

全局:全局所有接口都生效

'DEFAULT_PERMISSION_CLASSES': ['app01.permissions.CommonPermission'],

局部禁用:

permission_classes = [] 

views.py

class BookView(ViewSetMixin,RetrieveAPIView):
    queryset = Books.objects.all()
    serializer_class = BooksSerializers
    authentication_classes = [LoginAuth] #需要写一个认证类
    permission_classes = [CommonPermission] #认证和权限都可以加多个 多层

permission.py

#权限类  写一个类 重写方法 在方法中实现权限认证
from rest_framework.permissions import BasePermission


class CommonPermission(BasePermission):
    #重写has_permission方法 有权限返回True,没有权限返回False
    def has_permission(self,request,view):
        #实现权限的控制  -- 要先知道当前的登录用户是谁 request.user 前面认证返回的登录用户 就是这里的request.user
        if request.user.user_type == 1:
            return True
        else:
            #没有权限 可以放一个message
            self.message = '您是%s 您没有权限' %request.user.get_user_type_display()
            return False

频率组件

控制某个接口访问频率(次数)

查询所有接口 同一个ip一分钟只能访问5次

使用步骤

1.写一个频率类 继承SimpleRateThrottle

from rest_framework.throttling import BaseThrottle,SimpleRateThrottle

2.重写get_cache_key方法 返回什么 就以什么做限制 先用ip

#客户端的ip地址 从哪里拿 HttpRequest.META里取
return request.META.get('REMOTE_ADDR')

3.配置一个类属性

scope = 'lzy'

4.在配置文件中配置

 'DEFAULT_THROTTLE_RATES': {
        'lzy': '5/m',
    },

5.局部使用和全局使用

局部:只在某个视图类中使用【当前视图类管理的所有接口都使用

    throttle_classes = [CommonThrottle]

全局:全局所有接口都生效

'DEFAULT_THROTTLE_CLASSES': ['app01.throttling.CommonThrottle'],

局部禁用:

    throttle_classes = []

过滤排序

必须继承GenericAPIView及其子类才能使用这种方式

只有查所有才用到过滤

内置过滤类的使用 继承GenericAPIView

#查所有
class BooksView(ViewSetMixin,ListAPIView):
    queryset = Books.objects.all()
    serializer_class = BooksSerializers
    #这样就有过滤功能
    filter_backends = [SearchFilter]
    search_fields = ['name']  #按照名字模糊匹配 内置的 固定用法
    search_fields = ['name','price']  #按照名字或价格模糊匹配  其中有一个是相同的都会被筛选出来
ulr = 127.0.0.1:8000/api/v1/books/?seach=书

使用第三方django-filter实现过滤

# 安装:django-filter
#查所有
class BooksView(ViewSetMixin,ListAPIView):
    queryset = Books.objects.all()
    serializer_class = BooksSerializers
    #这样就有过滤功能
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['name'] #支持完整匹配 name=书
    
url = 127.0.0.1:8000/api/v1/books/?name=书2
url = 127.0.0.1:8000/api/v1/books/?name=书2&price=12  

自己定制过滤类实现过滤

查询价格大于100的书
url = http://127.0.0.1:8000/api/v1/books/?price_gt=100
       

1.定义一个过滤类 继承BaseFilterBackend

from django_filters.rest_framework import DjangoFilterBackend

2.重写filter_queryset方法

def filter_queryset(self,request, queryset, view):
    price_gt = request.query_params.get('price_gt',None)
    if price_gt:
        qs=queryset.filter(price__gt=int(price_gt))
        return qs
    else:
        return queryset

3.配置在视图类

filter_backends = [CommentFilter] 
'''可以定制多个 从左往右 依次执行'''

排序的使用

内置
from rest_framework.filters import OrderingFilter

    filter_backends = [OrderingFilter,CommentFilter]
    ordering_fields = ['price']
    #按照价格排序
    
支持查询的方法
	http://127.0.0.1:8000/api/v1/books/?ordering=price
    http://127.0.0.1:8000/api/v1/books/?ordering=-price
   http://127.0.0.1:8000/api/v1/books/?ordering=-id,pric

分页

只有查询才有分页

drf内置了三个分页器 之前的东西一样用

第一种:PageNumberPagination

from rest_framework.pagination import LimitOffsetPagination,CursorPagination,PageNumberPagination



class CommonPageNumberPagination(PageNumberPagination):
    page_size = 1 #每页显示两条
    page_query_param = 'page' #page=10 查询第10也的数据
    page_size_query_param = 'size' # page=10&size=5 查询第十页 每页显示5条
    max_page_size = 10   #每页最大的显示条数
    
    #配置在试图页即可
    
    pagination_class = CommonCursorPagination

第二种:LimitOffsetPagination

from rest_framework.pagination import LimitOffsetPagination,CursorPagination,PageNumberPagination



class CommonPageNumberPagination(LimitOffsetPagination):
    default_limit = 3 #每页显示3条
    limit_query_param = 'limit' #limit=3
    offset_query_param = 'offset' #offset=1 从第一个位置开始 取limit条
    max_limit = 5
    
    #配置在试图页即可
    
    pagination_class = CommonCursorPagination

app用

class CommonPageNumberPagination(CursorPagination):
    cursor_query_param = 'cursor'  #查询参数
    page_size = 2 #每页多少条
    ordering = 'id'  #排序字段
    #配置在试图页即可
    
    pagination_class = CommonCursorPagination
#游标分页 只能下一页 上一页 不能跳到中间 但他的效率最高 大数据量分页 使用这种较好

有关drf 认证组件、权限组件、频率组件的更多相关文章

  1. ruby - rbenv 安装权限被拒绝 - 2

    大家好,我正在尝试设置一个开发环境,并且我一直在关注以下教程:Linktotutorial我做得不是很好,除了最基本的版本控制内容外,我对终端命令没有任何实际经验。我点击了第一个链接并尝试运行source~/.bash_profile我得到了错误;mkdir:/usr/local/rbenv/shims:权限被拒绝mkdir:/usr/local/rbenv/versions:权限被拒绝现在每次我加载终端时都会出现错误。bash_profile的内容;exportPATH=/usr/local/rbenv/bin:$PATHexportRBENV_ROOT=/usr/local/rbe

  2. ruby - token 认证 - 2

    简单代码require'net/http'url=URI.parse('getjson/otherdatahere[link]')req=Net::HTTP::Get.new(url.to_s)res=Net::HTTP.start(url.host,url.port){|http|http.request(req)}putsres.body只是想知道如何在phpcURL中放置身份验证token,我是这样做的    curl_setopt($ch,CURLOPT_HTTPHEADER,array('Authorization:Bearerxxx'));//Bearertokenfora

  3. ruby-on-rails - 为什么用户必须输入 7 位数的 Twitter PIN 才能授予我的应用程序访问权限? - 2

    我正在为我的用户实现一些ruby​​onrails代码推特内容。我正在创建正确的oauth链接...类似http://twitter.com/oauth/authorize?oauth_token=y2RkuftYAEkbEuIF7zKMuzWN30O2XxM8U9j0egtzKv但在我的测试帐户授予对twitter的访问权限后,它会弹出一个页面,上面写着“您已成功授予对.我不知道用户应该在哪里输入此PIN以及他们为什么必须这样做。我认为这不是必要的步骤。Twitter应该将用户重定向到我在应用程序设置中提供的回调URL。有谁知道为什么会这样?更新我找到了thisarticle声明我需

  4. ruby - HTTParty 摘要认证 - 2

    谁能提供一个使用HTTParty和digestauth的例子?我在网上找不到例子,希望有人能提供一些帮助。谢谢。 最佳答案 您可以在定义类时使用digest_auth方法设置用户名和密码classFooincludeHTTPartydigest_auth'username','password'end 关于ruby-HTTParty摘要认证,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questi

  5. ruby - rbenv:权限被拒绝 - 2

    我正在关注Ryan的RailsCast第339集。我已经安装了rbenv并且可以运行ruby-v。我退出了我的session,当我试图返回时(通过root的sudeployer,我得到了这个错误/home/deployer/.rbenv/bin/rbenv:line20:cd:/root:Permissiondenied这是rbenv文件:#!/usr/bin/envbashset-e[-n"$RBENV_DEBUG"]&&set-xresolve_link(){$(type-pgreadlinkreadlink|head-1)"$1"}abs_dirname(){localcwd="

  6. ruby - 按数组中出现的频率排序 - 2

    有没有一种有效的方法来做到这一点。我有一个数组a=[1,2,2,3,1,2]我想按升序输出出现的频率。示例[[3,1],[1,2],[2,3]]这是我的ruby​​代码。b=a.group_by{|x|x}out={}b.eachdo|k,v|out[k]=v.sizeendout.sort_by{|k,v|v} 最佳答案 a=[1,2,2,3,1,2]a.each_with_object(Hash.new(0)){|m,h|h[m]+=1}.sort_by{|k,v|v}#=>[[3,1],[1,2],[2,3]]

  7. ruby-on-rails - 在服务器上没有互联网访问权限的 Capistrano 部署 - 2

    如何使用Capistrano将Rails应用程序部署到无法访问外部网络或存储库的生产或暂存服务器?我已经设法完成部署的一半,并意识到Capistrano没有在我的本地机器上下载gitrepo,但它首先连接到远程服务器并尝试在那里下载Git存储库。我希望有一个类似Javaee的构建系统,其中创建可交付成果并将该可交付成果发送到服务器。就像您构建.ear文件并将其部署到您想要的任何服务器上一样。显然在RoR中,你被迫(据我所知)在该服务器上构建应用程序,在那里创建一个gem存储库,在那里克隆最新的分支等等。有什么方法可以将准备运行的包发送到远程服务器吗? 最佳答

  8. ruby-on-rails - 使用 Ruby on Rails 处理回形针文件夹和文件权限 - 2

    我在运行Ubuntu10.04LTS的远程VPS机器上以生产模式运行RubyonRails3.0.9(在开发模式下,我在MACOSSnow上使用RoRLeopard),我想知道如何管理以下场景。我使用Apache2和PhusionPassenger并且我将虚拟主机设置为如下所示:ServerNameproject_name.comDocumentRoot/srv/www/project_name.com/publicAllowOverrideallOptions-MultiViews此外,我使用Paperclipgem,由于网上很多人在生产模式下使用它,我在处理(图像)文件时遇到以下错

  9. ruby - RVM:在系统范围安装中从 .rvmrc 文件加载 gemset 时权限被拒绝 - 2

    我创建了一个包含自定义gemset的项目特定.rvmrc文件(使用命令rvm--rvmrc--create1.9.2@registration):#excerptof.rvmrc...environment_id="ruby-1.9.2@registration"if[[-d"${rvm_path:-$HOME/.rvm}/environments"\&&-s"${rvm_path:-$HOME/.rvm}/environments/$environment_id"]]then\."${rvm_path:-$HOME/.rvm}/environments/$environment_id

  10. ruby-on-rails - 在 Ruby on Rails 中根据频率对数组进行排序 - 2

    我有一个嵌套的数字数组,排列如下:ids=[[5,8,10],[8,7,25],[15,30,32],[10,8,7]]我只需要一个包含所有键的数组,无需重复,所以我使用了这个:ids=ids.flatten.uniq产生这个:ids=[5,8,10,7,25,15,30,32]由于我使用了.uniq,它消除了重复值。但是,我想根据它们在子数组中出现的频率来对值进行排序,而不是它们碰巧处于的顺序——所以像这样:ids=[8,10,7,5,25,15,30,32] 最佳答案 应该这样做:ids.flatten.group_by{|i|

随机推荐