认证、权限
认证
-登录认证---》某个接口必须登录后才能访问
-登录接口---》登录成功返回随机字符串---》携带随机字符串【认证】 通过,再继续访问某个接口
-读APIView源码时,三大认证---》视图类的方法之前执行的----》drf提供了很方便的写认证
'''写一个登录接口'''
-用户表,用户token表
-前端传入用户名密码----》视图类---》登录方法---》校验用户名密码是否正确,如果正确 生成随机字符串存入数据库---》把随机字符串返回给前端
'''随便写个接口---》登录后才能访问'''
'写认证类'
-第一步:写一个类,继承BaseAuthentication
-第二步:在类中重写authenticate方法
-第三步:在方法中做验证,如果通过,返回两个值,如果不通过,抛AuthenticationFailed的异常
'使用认证类'
-局部使用-->视图类中
class BookView(APIView):
authentication_classes = [LoginAuth,]
-全局使用---》配置文件
REST_FRAMEWORK = {
# 全局使用认证类
'DEFAULT_AUTHENTICATION_CLASSES':['app01.auth.LoginAuth',]
}
-局部禁用
class BookView(APIView):
authentication_classes = []
'前端调用接口时'
http://127.0.0.1:8000/user/books?token=27954a0e-9b0b-442d-8aff-839ec9f70960
登录接口
模型类
class User(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=32)
class UserToken(models.Model):
token = models.CharField(max_length=32) # 用户登录成功签发的随机字符串
user = models.OneToOneField(to='User',on_delete=models.CASCADE)
路由
from rest_framework.routers import SimpleRouter
from .views import UserView,BookView
router=SimpleRouter()
router.register('user',UserView,'user')
urlpatterns = [
]
urlpatterns+=router.urls
视图类
class UserView(ViewSet):
authentication_classes = [] # 局部禁用
# 127.0.0.1:8080/user/user/login--->post
@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:
# 登录成功
# 生成一个随机字符串---》uuid--》生成一个随机不重复的值
token = str(uuid.uuid4()) # python 动态强类型
# 存到UserToken表中---》两种情况:之前有了就更新,之前没有就新增
# 有就更新,没有就修改
# defaults=None, **kwargs:传入的去查询,如果能查到使用defaults给的更新
UserToken.objects.update_or_create(user=user, defaults={'token': token})
# UserToken.objects.update_or_create( defaults={'token': token},kwargs={'user':user})
return Response({'code': 100, 'msg': '登录成功', 'token': token})
else:
return Response({'code': 101, 'msg': '用户名或密码错误'})
认证类
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from .models import UserToken
class LoginAuth(BaseAuthentication):
def authenticate(self, request):
# 做验证,验证用户是否登录
# 放到请求地址中/请求头中
token=request.query_params.get('token')
# 去数据库查 token在不在
user_token=UserToken.objects.filter(token=token).first()
if user_token:
# 验证通过了,返回两个值,第一个值是当前登录用户,第二个值是token
return user_token.user,token
else:
# 验证失败
raise AuthenticationFailed('小伙子,您没有登录,不能访问')
重点
认证类:
-第一步:写一个类,继承BaseAuthentication
-第二步:在类中重写authenticate方法
def authenticate(self, request):
# 做验证,验证用户是否登录
# 放到请求地址中/请求头中
token=request.query_params.get('token')
# 去数据库查 token在不在
# 验证通过了,返回两个值,第一个值是当前登录用户,第二个值是token
-第三步:在方法中做验证,如果通过,返回两个值,如果不通过,抛AuthenticationFailed的异常
# 验证失败
raise AuthenticationFailed('小伙子,您没有登录,不能访问')
-----------------------------------------------------
写登录功能时:
-取出用户名密码---》去数据库查询---》有就登录成功(生成随机字符串存入数据),没有就登录失败
-登录成功,生成一个随机字符串---》uuid--》生成一个随机不重复的值
-token = str(uuid.uuid4()) # python 动态强类型
# 存到UserToken表中---》两种情况:之前有了就更新,之前没有就新增
# 有就更新,没有就修改
# defaults=None, **kwargs:传入的去查询,如果能查到使用defaults给的更新
UserToken.objects.update_or_create(user=user, defaults={'token': token})
-继承BaseAuthentication
权限
权限类的写法
-第一步:写一个类,继承BasePermission
-第二步:重写has_permission方法
-第三步:在has_permission中,进行权限的判断,如果有权限,返回True,如果没有权限,返回False,返回的中文提示信息,使用message字段标识
权限类的使用
-局部使用-->视图类中
class BookView(APIView):
permission_classes = [PermissionAuth,]
-全局使用-->配置文件
REST_FRAMEWORK = {
# 全局使用认证类
'DEFAULT_PERMISSION_CLASSES':['app01.auth.PermissionAuth',]
}
-局部禁用
class BookView(APIView):
permission_classes = []
补充
# python 是动态强类型语言
# go 是静态强类型语言
# java 是静态强类型语言---》隐士类型转换
#js 是动态弱类型语言
# 动态:解释型语言
# 强弱指的是:数据类型强:不同类型之间不允许之间运算
# 弱类型:不同类型之间不需要转换可以之间运算
'''健壮性----鲁棒性'''
健壮性:系统在不正常输入情况下仍能表现正常的程度。
处理未期望的行为和错误终止;
即使终止执行,也要准确/无歧义地向用户展示错误信息
错误信息有助于debug
正确性:程序按照spec加以执行的能力,是最重要的质量指标
正确性 vs 健壮性
正确性,永不给用户错误的结果;健壮性,尽可能保持软件运行而不是总是退出
正确性倾向于直接报错,健壮性倾向于容错
对外的接口,倾向于健壮性;对内的实现,倾向于正确性