drf——登录功能、认证、权限、频率组件(Django转换器、配置文件作用)

发布时间 2023-05-25 08:38:54作者: 抱紧小洪

Django转换器、配置文件作用

# django转换器 2.x以后 为了取代re_path
	int	 path('books/<int:pk>')--->/books/1--->pk=1--->当参数传入视图类的方法中
    str  path('books/<str:name>')
    path path('media/<path:path>',serve,{'document_root':'路径'} ),
    slug
    uuid 
    
# django配置文件
1.Django项目要运行 优先执行配置文件的内容 做一下配置加载工作 manage.py中
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'drf_day07.settings')
    ##Django项目配置文件的路径可以修改 配置文件名也可以修改 但一般不会去改
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', '配置文件路径')
        
2.任何一个Django项目都有两套配置
    一套是项目自己的 自己有哪个配置参数 优先用自己的
    一套是内置的(Django内置的)
        
3.配置参数的作用
    # 1  项目的根路径  
        BASE_DIR
    # 2 密钥---》djagno中涉及到加密的,大部分都会用这个密钥
        SECRET_KEY 
    # 3 是否开启调试模式 上线一定关闭 只要是调试模式,访问路径不存在时,会显示出所有能访问的路径,视图类出了异常,浏览器中能看到
        DEBUG = True 默认是True
    # 4 项目是要部署在某个服务器上 这个列表写部署服务器的ip地址 *表示任何地址都可以
    	ALLOWED_HOSTS = ['*'] 默认是空的
    # 5 内置 我们自己写的app
        INSTALLED_APPS = [
            'django.contrib.admin',  # 后台管理---》很多表不是它的,是别的app的
            'django.contrib.auth',  # auth 模块,UsrInfo表----》有6个表
            'django.contrib.contenttypes',  # 有个django_content_type表是,这个app的
            'django.contrib.sessions',  # session相关的
            'django.contrib.messages',  # 消息框架
            'django.contrib.staticfiles',  # 静态文件开启的app
            'app01.apps.App01Config',  # app01 自己写的app要在这里注册
            'rest_framework'  # drf 浏览器访问需要在这里注册
        ]	
    # 6 中间件
   		MIDDLEWARE = [
    	'django.middleware.security.SecurityMiddleware',
    	'django.contrib.sessions.middleware.SessionMiddleware',  # session相关
    	'django.middleware.common.CommonMiddleware',  # 公共
    	'django.middleware.csrf.CsrfViewMiddleware',
    	'django.contrib.auth.middleware.AuthenticationMiddleware',
    	'django.contrib.messages.middleware.MessageMiddleware',
    	'django.middleware.clickjacking.XFrameOptionsMiddleware',
	]   
    # 7 根路由
    	ROOT_URLCONF = 'drf_day07.urls'  # 默认是urls 也可以改文件名 一般不改
    # 8 模板文件所在路径
    	TEMPLATES = [
            ...
        ]
    # 9 项目上线,运行application,后面再说
    	WSGI_APPLICATION = 'drf_day07.wsgi.application'
    # 10 数据库配置
    	DATABASES = {
            ...
        }
    # 11 做国际化
    	LANGUAGE_CODE = 'zh-hans'  # 语言
        TIME_ZONE = 'Asia/Shanghai' # 时区
        USE_I18N = True
        USE_L10N = True
        USE_TZ = True
    # 12 静态文件
		STATIC_URL = '/static/'
    # 13 表中,默认可以不写id,id主键自增,之前全是AutoField,长度很短
    	DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

登录功能

表模型

class UserInfo(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=64)

class UserToken(models.Model):
    token = models.CharField(max_length=64)
    user = models.OneToOneField(to=UserInfo,on_delete=models.CASCADE)

视图类

class UserView(ViewSet):
    @action(methods=['POST'],detail=False)
    def login(self,request):
        username = request.data.get('username')
        password = request.data.get('password')
        user_obj = UserInfo.objects.filter(username=username,password=password).first()
        if user_obj:
            # 登录成功
            # 1 生成一个随机字符串 token
            token = str(uuid.uuid4())
            # 2 把token存到表中 UserToken表有值就更新 没有值就增加
            UserToken.objects.update_or_create(user=user_obj,defaults={'token':token})
            return Response({'code': 100, 'msg': '登录成功', 'token': token})
        else:
            return Response({'code': 101, 'msg': '用户名或密码错误'})

路由

# 方式一:
path('login/',views.UserView.as_view({'post':'login'})),
# 路由如果这样写 是不需要使用action装饰器

# 方式二:自动生成路由---》视图类中一定要用action装饰器
from rest_framework.routers import SimpleRouter

router = SimpleRouter()
router.register('user',views.UserView,'user')

urlpatterns = [
    path('admin/', admin.site.urls),
    # path('',include(router.urls))
]
# http://127.0.0.1:8000/user/login/
urlpatterns += router.urls

认证组件

# APIView执行流程
	在视图类的方法之前 执行了三大认证

# 认证:登录认证
	登录认证---》控制某个接口必须登录后才能访问
    
# 认证组件使用步骤(固定用法)
	1 写一个类 继承BaseAuthentication
    	from rest_framework.authentication import BaseAuthentication
    2 在类中重写authenticate方法
    	class LoginAuth(BaseAuthentication):
    		def authenticate(self, request):  # 父类中有 一定要重写 否则报错
        	# 校验用户是否登录---》请求中携带我给的token 就是登录了
        	# token在哪携带 是接口规定的
        	# 1.规定待在请求地址中---》讲这个
        	# 2.规定带在请求头中(这个多)
        	# 3.规定待在请求体中
        	# 取出token META HTTP_TOKEN
        	'''方法一 从请求地址中取'''
        	# token = request.query_params.get('token')
        	'''方法二 从请求头中取'''
        	token = request.META.get('HTTP_TOKEN')
        	# 去数据库中 根据token 校验有没有数据
        	user_token = UserToken.objects.filter(token=token).first()
        	if user_token:
            	# 如果有就是已经登录
            	# print(request.user)  认证没有结束之前不能打印request.user 否则会递归
            	user = user_token.user
            	print(user_token.user)  # UserInfo object (1)
            	return user,token
        	else:
            	# 说明它带的token不对的
            	raise AuthenticationFailed('你没有登录,不能访问')
    3 在方法中 完成登录认证 如果没有登录则抛异常
    4 如果是登录的 返回登录用户和token
    
    5 在视图类中 使用认证类(局部使用)
		class BookView(APIView):
            authentication_classes = [LoginAuth,]
    6 全局使用:
    ### 重点:不要在配置文件中,导入莫名其妙的包
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'app01.auth.LoginAuth'
        ],
    }
    7 全局使用认证后 局部禁用
    class UserView(ViewSet):
        authentication_classes = []  # 列表置为空就可以
    8 认证类的使用顺序
    	优先用视图类配置的
        其次用项目配置文件
        最后用drf默认的配置
        
# 小重点:一旦通过认证 在request中就有当前登录用户 request.user为当前登录用户
	def get(self,request):
        print(request.user.username,'访问了接口')

权限组件

# 大家都登录了,但有的功能(接口),只有超级管理员能做,有的功能所有登录用户都能做----》这就涉及到权限的设计了

# 权限设计:比较复杂---》有acl,rbac,abac。。。

# 咱们现在只是为了先讲明白,drf的权限组件如何用,咱们先以最简单的为例
	查询所有图书:所有登录用户都能访问(普通用户和超级管理员)
        没有权限控制
    删除图书 只有超级管理员能访问
    	给其他用户设置的权限
        
# 权限类的使用步骤
	1.写一个类 继承BasePermission
    	from rest_framework.permissions import BasePermission
    2.在类中写方法:has_permission
      	如果有权限 就返回True
        如果没有权限 就返回False
        错误信息是self.message='字符串'
        class AdminPermission(BasePermission):
    		def has_permission(self, request, view):
        	# 如果有权限 就是返回True 没有权限 返回False
        	# 判断user_type是不是1 根据当前登录用户
        	# request.user # 就是当前登录用户 一旦来到这里,登录认证就通过了
        	if request.user.user_type == 1:
            	return True
        	else:
            	# 错误信息
            	self.message = '你好:%s,你没有权限' % request.user.username
            	return False
        
    3.局部使用
    class BookDetailView(APIView):
        permission_classer = [AdminPermission,]
    4.全局使用
        REST_FRAMEWORK = {
        'DEFAULT_PERMISSION_CLASSES': [
            'app01.permission.AdminPermission'
        ],
        }
    5.局部禁用
    class BookView(APIView):
        permission_classer = []

频率组件

# 限制访问频次
	比如某个接口 一分钟只能访问5次 超过了就得等
    按ip地址 限制
    按用户id 限制

# 频率类的使用步骤
	1.写个类 继承:SimpleRateThrottle
    2.重写某个方法:get_cache_key
    	可以返回ip或者用户id
        返回什么就以什么做频率限制
        
    3.写一个类属性 随意命名一个名字
    	scope = 'lqz'
    4.在配置文件中配置
    	'DEFAULT_THROTTLE_RATES': {
        	'lqz': '3/m' # 一分钟访问3次
    	},
    5.全局用
    	'DEFAULT_THROTTLE_CLASSES': [
            
        ],
    6.局部用
    class BookView(APIView):
        throttle_classes = [MyThrottle]