DRF - 认证
认证组件
在DRF中,提交请求的时候不需要携带csrf,因为有token认证了
认证:通过判断token,来判断用户是否登录
1.登录接口编写
- 需要和数据库交互,但是不需要序列化,所以使用ViewSetMixin + APIView
使用action装饰器装饰
-
发送post请求,取出前端传入的数据-->request.data中获取
-
判断是否成功 将session存在UserToken中存储登录状态
如果存在则更新,不存在就更新
-
返回给前端
(1)models.py - 模型层
建立User和UserToken表
class User(models.Model): username = models.CharField(max_length=32) password = models.CharField(max_length=32) class UserToken(models.Model): # 跟User是一对一,存放token信息 token = models.CharField(max_length=32) user = models.OneToOneField(to='User', on_delete=models.CASCADE, null=True) # user :反向,表名小写,所有有user字段
(2)urls.py - 路由
通过路由自动生成接口 - /api/v1/user/login/
from rest_framework.routers import SimpleRouter # 生成路由 router = SimpleRouter() router.register('user', views.UserView, 'user') urlpatterns = [ path('admin/', admin.site.urls), path('api/v1/', include(router.urls)), ]
(3)views.py - 视图层
登录接口,自动生成路由 + ViewSet
- 由于登录功能,不用序列化数据,所以可以继承ViewSet
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() # 1.判断用户名是否存在 if user: # 用户名存在 # 1.1 生成一个随机字符串:通过uuid4生成 token = str(uuid.uuid4()) # 1.2 生成之后将其存在user_token中,用于登录的时候校验 # 如果之前没有登录过,则没有token则新建一个。 # 如果有token则更新token ==> 使用 update_or_create(传对象,defaults={'token':token)方法 UserToken.objects.update_or_create(user=user,defaults={'token':token}) return Response({'code': 100, 'msg': '用户登录成功'}) else: return Response({'code': 101, 'msg': '用户名或者密码错误'})
2.认证功能
自定认证的使用步骤
(1)编写一个认证类,继承【认证模块】中的BaseAuthentication
from rest_framework.authentication import BaseAuthentication
(2)重写authenticate
方法,来进行登录认证
- 判断用户是否提供了token
- 如果提供了token,则判断token是否一致
一般token都放在【请求头】中,而通过request.META来获取
(3)如果认证成功,返回【当前登录用户,token】
(4)如果认证不通过则通过AuthenticationFailed
抛出异常
from rest_framework.exceptions import AuthenticationFailed
(5)全局认证与局部认证、局部禁用
3.全局认证与局部认证、局部禁用
全局、局部、默认配置的优先级
1.局部(视图类中)
2.全局(
settings.py
中)3.默认(默认配置文件中)
认证类可以设置是全局使用或者是局部使用。
并且认证类可以配置多个,按照从前向后到顺序执行,如果前面有返回值,认证就不继续往下执行了
(1)局部认证:对于对应的视图类生效
在视图类中,通过authentication_classes
来进行限制认证
class BookDetailView(ViewSetMixin, RetrieveAPIView): """查询单个""" queryset = Book.objects.all() serializer_class = BookSerializer "局部认证" authentication_classes = [LoginAuth]
(2)全局认证:对于全局的视图类生效
settings.py在配置文件中配置
REST_FRAMEWORK = { # 【认证】的全局配置 'DEFAULT_AUTHENTICATION_CLASSES':'app01.authenticate.LoginAuth', }
(3)全局认证 + 局部禁用
settings.py 在配置文件中配置
REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ["mine.x_authenticate.LoginAuth", ] }
views.py的视图类中
当全局都配置了需要认证后,只要在局部的视图类中authentication_classes
空即可完成局部禁用的功能
class BookView(APIView): authentication_classes = [] ...
不要在配置中乱导东西??
例如:在配置文件中导入
from app01.authenticate import LoginAuth
则会报错,这是因为app01还没在程序中加载成功
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
4.代码演示
authenticate.py
- 自己编写认证类
# 导入认证类 from rest_framework.authentication import BaseAuthentication # 导入认证失败时抛出的异常字段 from rest_framework.exceptions import AuthenticationFailed # 导入UserToken表 from .models import UserToken class LoginAuth(BaseAuthentication): def authenticate(self, request): """ 阅读源码我们可以知道,需要重写 authenticate 方法,来进行登录认证。 代码逻辑:如果请求中携带了正确的token则可以登录成功【token放在地址栏中】 """ # 1.获取token token = request.query_params.get('token', None) # 2.判断是否存在token if token: # 3.获取UserToken表中的token user_token = UserToken.objects.filter(token=token).first() # 4.判断UserToken表中是否记录了token if user_token: # 5.如果存在token则表示用户已经登录,则需要【固定】返回两个数据:(1)当前登录用户 (2)token return user_token.user, token else: # 6.如果没有登录则抛出异常 raise AuthenticationFailed('用户未登录,token认证失败') else: # 7.前端没有传token抛出异常 raise AuthenticationFailed('token未携带')
views.py
- 视图类
from .serializer import BookSerializer # 导入认证类 from .authenticate import LoginAuth "2 查询所有 和 查询单个 的接口" # 导入查询所有和查询单个的视图子类 from rest_framework.generics import ListAPIView, RetrieveAPIView # 自动生成路由的魔法类 from rest_framework.viewsets import ViewSetMixin class BookView(ViewSetMixin, ListAPIView): """查询所有""" queryset = Book.objects.all() serializer_class = BookSerializer class BookDetailView(ViewSetMixin, RetrieveAPIView): """查询单个""" queryset = Book.objects.all() serializer_class = BookSerializer "局部登录认证" authentication_classes = [LoginAuth]
urls.py
- 路由
路由通过自动生成
# 生成路由 router = SimpleRouter() router.register('user', views.UserView, 'user') urlpatterns = [ path('api/v1/', include(router.urls)), ]
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY