认证组件
登录功能
写登录的时候,可以使用auth提供的user表,也可以自定义
===》自定义
写登录接口,登录成功,要有标志生成一个随机字符串,放在表中,以后他只要带这个随机字符串过来,我们就认为是这个人登录的
### ### ### ### ### ### ### 视图类### ### ### ### ### ### ### ### ### ### ### ### ### from rest_framework.views import APIView from rest_framework.generics import GenericAPIView from rest_framework.viewsets import ViewSetMixin, ViewSet from rest_framework.response import Response from rest_framework.decorators import action from .models import User, UserToken import uuid # class UserView(ViewSetMixin,APIView): class UserView(ViewSet): @action(methods=['POST'], detail=False) # /user/login/ post 请求就会执行 def login(self, request, *args, **kwargs): # 前端传入用户名密码 username = request.data.get('username') password = request.data.get('password') user = User.objects.filter(username=username, password=password).first() if user: # 生成一个随机字符串,返回给前端,并且要把随机字符串存到token表中 # 随机字符串使用uuid生成 token = str(uuid.uuid4()) # 把随机字符串存到token表中会有两种情况(如果之前没有登录过就是新增,如果之前登录过修改) # 先去UserToken表中,根据user查,如果能查到,就修改,查不到就新增一条记录 ##### 方式一:麻烦方式 # user_token=UserToken.objects.filter(user=user).first() # if user_token: # user_token.token=token # user_token.save() # else: # UserToken.objects.create(user=user,token=token) ## 方式二:通过user去UserToken表中查,如果能查到用defaults的更新,如果查不到,就用user和defaults新增一条记录 UserToken.objects.update_or_create(defaults={'token': token}, user=user) return Response({'code': 100, 'msg': '登录成功', 'token': token, 'username': user.username}) else: return Response({'code': 101, 'msg': '用户名或密码错误'}) ### ### ### ### ### ### ### 路由### ### ### ### from rest_framework.routers import SimpleRouter router = SimpleRouter() router.register('user', UserView, 'user') urlpatterns = [ path('admin/', admin.site.urls), path('', include(router.urls)), ]
认证组件
认证有什么作用?
一些接口,想限制登录后才能访问,没登录不能访问
做登录认证,限制如果没登录,不允许访问该接口
drf中,认证如何使用?
1. 写一个类,继承BaseAuthentication
2. 类中重写:authenticate
3. 在authenticate完成登录认证, 如果登录了。返回两个值,如果没登录抛异常
4. 在视图类中配置使用
class BookView(ViewSet): authentication_classes = [LoginAuth]
如果登录了,在视图类的方法中,能拿出当前登录用户
request.user
auth.py
from .models import UserToken ''' 按照如下步骤写 1. 写一个类,继承BaseAuthentication 2. 类中重写:authenticate方法 3. 在authenticate完成登录认证,如果登录了,返回两个值,如果没登录抛异常 4. 在视图类中配置事宜 ''' from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed class LoginAuth(BaseAuthentication): def authenticate(self, request): # 如何知道当前请求这个人是登录了? # 拿到前端传入的token:当时给的随机字符串===》去UserToken表中查,如果能查到,说明就是这个人在访问,如果查不到,说明这个人没有登录过 # 前端传入的token从哪拿?如何拿?===》后端定的:1 请求地址中 2. 请求体中 3. 请求头中 token = request.query_params.get('token') user_token = UserToken.objects.filter(token=token).first() if user_token: # 是登录状态 return user_token.user, token # 返回两个值,第一个是当前登录用户,第二个是前端token else: raise AuthenticationFailed('您没有登录')
视图类
from django.shortcuts import render # Create your views here. # 路由自动生成吗? 自动生成继承:ViewSetMixin 我想 # 要不要序列化,要不要跟数据库打交道,继承GenericAPIView:查出所有数据(只要一条),还要写个序列化类() from rest_framework.views import APIView from rest_framework.generics import GenericAPIView from rest_framework.viewsets import ViewSetMixin, ViewSet from rest_framework.response import Response from rest_framework.decorators import action from .models import User, UserToken import uuid from .auth import LoginAuth # class UserView(ViewSetMixin,APIView): class UserView(ViewSet): @action(methods=['POST'], detail=False) # /user/login/ post 请求就会执行 def login(self, request, *args, **kwargs): # 前端传入用户名密码 username = request.data.get('username') password = request.data.get('password') user = User.objects.filter(username=username, password=password).first() if user: # 生成一个随机字符串,返回给前端,并且要把随机字符串存到token表中 # 随机字符串使用uuid生成 token = str(uuid.uuid4()) # 把随机字符串存到token表中会有两种情况(如果之前没有登录过就是新增,如果之前登录过修改) # 先去UserToken表中,根据user查,如果能查到,就修改,查不到就新增一条记录 ##### 方式一:麻烦方式 # user_token=UserToken.objects.filter(user=user).first() # if user_token: # user_token.token=token # user_token.save() # else: # UserToken.objects.create(user=user,token=token) ## 方式二:通过user去UserToken表中查,如果能查到用defaults的更新,如果查不到,就用user和defaults新增一条记录 UserToken.objects.update_or_create(defaults={'token': token}, user=user) return Response({'code': 100, 'msg': '登录成功', 'token': token, 'username': user.username}) else: return Response({'code': 101, 'msg': '用户名或密码错误'}) class BookView(ViewSet): authentication_classes = [LoginAuth] # 这个认证类,管理了当前类下所有的方法 def list(self, request): print(request.user.username) # 当前登录用户 return Response("你好:%s,你看到了好多书啊"%request.user.username)
路由
from rest_framework.routers import SimpleRouter router = SimpleRouter() router.register('user', UserView, 'user') router.register('books', BookView, 'books') urlpatterns = [ path('', include(router.urls)), ]
小结
1. 认证类要写好,使用
配置在视图类上===》局部使用
配置文件中配置===》全局使用===》所有接口都必须登录后才能用
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'app01.auth.LoginAuth'
],
}
局部禁用:
class UserView(ViewSet)
authentication_class = []
2. 写的认证类:
要重写authenticate方法,必须返回两个参数:当前登录用户:user_token.user,用户的token ===》后续在视图类中:request.user 就是认证类返回的第一个参数,request.auth 就是认证类返回的第二个参数
3. 如果认证失败,抛异常AuthenticationFailed,会被drf捕获,处理,不会报错到前端
4. 前端传入的token,从哪取?
后端定的,我们这个项目是从请求地址中取
还可以从请求头或者请求体中取
5. UserToken.objects.update_or_create
权限组件
系统中:有普通用户,超级用户,超级管理员,他们都登录了,又分权限,有的人有权限,就能访问这个接口,没权限,就不能访问
''' 使用步骤: 1. 写一个类,继承 BasePermission 2. 重写 has_permission 3. 在方法中校验用户是否有权限,如果有,就返回True,如果没有,就返回False 由于他的执行是在认证之后,所有从request.user中取出当前的用户,判断权限 4. 在视图类中局部使用,在settings中全局使用,局部可以禁用''' class PublishView(ViewSet): permission_classes = [UserPermission] REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'app01.auth.LoginAuth' ], 'DEFAULT_PERMISSION_CLASSES': [ 'app01.permissions.UserPermission', ], }
视图类
from rest_framework.permissions import BasePermission # 1 写一个类,继承 BasePermission # 2 重写 has_permission # 3 在方法中校验用户是否有权限,如果有,就返回True,如果没有,就返回False # 4 class UserPermission(BasePermission): def has_permission(self, request, view): # request 当次请求的request, 新的,它是在认证类之后执行的,如果认证通过了request.user 就是当前登录用户 # 拿到当前登录用户,查看它的类型,确定有没有权限 if request.user.user_type == 3: return True else: self.message = '您的用户类型是:%s,您没有权限操作' % (request.user.get_user_type_display()) return False
补充:Django项目国际化
# 配置文件中--->以后所有英文都会转成中文 INSTALLED_APPS = [ 'rest_framework' ] LANGUAGE_CODE = 'zh-hans' TIME_ZONE = 'Asia/Shanghai' USE_I18N = True USE_L10N = True USE_TZ = False
频率组件
作用:控制一个接口一定时间段内的访问次数
对接口进行访问次数限制
# 使用步骤: # 1. 写一个类,继承SimpleRateThrottle # 2. 重写get_cache_key,返回什么,就以什么做限制:IP地址,用户id限制 3. 写一个类属性 scope = 'drf_day08' # 4. 配置文件中配置 ''' 'DEFAULT_THROTTLE_RATES': { 'drf_day08': '3/m', # 一分钟访问三次 5/s,m,h,d }, ''' # 5. 局部使用,全局使用,局部禁用 class PublishView(ViewSet): throttle_classes = [IPRateThrottle] # 6 全局使用 'DEFAULT_THROTTLE_CLASSES': ['app01.throttling.IPRateThrottle'],
视图类
from rest_framework.throttling import SimpleRateThrottle # 1 写一个类,继承SimpleRateThrottle # 2 重写get_cache_key,返回什么,就以什么做限制: IP地址,用户id限制 # 3 写一个类属性 scope = 'drf_day08' # 4 配置文件中配置 ''' 'DEFAULT_THROTTLE_RATES': { 'drf_day08': '3/m', # 一分钟访问三次 }, ''' # 5 局部使用,全局使用,局部禁用 class IPRateThrottle(SimpleRateThrottle): scope = 'drf_day08' # 写一个类属性 def get_cache_key(self, request, view): # 返回ip,以ip地址限制 print(request.META) return request.META.get('REMOTE_ADDR')
排序
只有5个接口中的查询所有,才涉及到排序
使用步骤:
1. 必须写在继承:GenericAPIView类的视图类中才行
2. 配置类属性:
filter_backends = [OrderingFilter] ordering_fields = ['id', 'user_tyoe'] # 可以排序的字段
3. 使用:
http://127.0.0.1:8000/user/?ordering=user_type #用户类型升序排
http://127.0.0.1:8000/user/?ordering=-user_type #用户类型降序排
http://127.0.0.1:8000/user/?ordering=user_type,-id#先按用户类型升序排,如果用户类型一样,再按id降序排
标签:登录,request,认证,token,user,组件,import,权限,### From: https://www.cnblogs.com/zfq132/p/17682905.html