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)),
]
posted @   Duosg  阅读(69)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示