Django-drf项目初始化:跨域、认证权限过滤、static静态资源路由,mysql数据库连接,登录注册功能
码云地址:https://gitee.com/liuhaizhang/drf-project-initialization
项目目录结构:
study_drf
-home
-static
-study_drf
-util
-manage.py
一、安装的包
pip install django #drf基于django
pip install djangorestframework #drf框架
pip install mysqlclient #连接数据库
pip install djangorestframework-jwt #认证
pip install django_filter #过滤
pip install django-cors-headers #跨域问题
二、命令行创建
#创建django项目
python django-admin startproject 项目名#创建应用
python manage.py startapp 应用名
三、配置mysql和创建用户表
3.1、在settings.py中配置好mysql
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'study_drf',
"USER":"root",
"PASSWORD":"Huawei@123",
"PORT":3306,
"HOST":"127.0.0.1"
}
}
3.2、创建用户表
from django.db import models
# Create your models here.class UserModel(models.Model):
username = models.CharField(max_length=100,verbose_name='账户',unique=True)
password = models.CharField(max_length=256,verbose_name='密码')
role = models.SmallIntegerField(choices=((1,'管理员'),(2,'普通用户')))
phoneNumber = models.CharField(max_length=11,verbose_name='手机号码',unique=True)
realName = models.CharField(max_length=128,verbose_name='用户姓名')
3.3、执行数据库迁移命令
#生成迁移文件
python manage.py makemigrations
#将生成的迁移文件真正执行到数据库中,生成对应的表格或修改数据库表
python manage.py migrate
四、settings.py 配置
4.1、配置跨域
#1、注册应用
INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','corsheaders', #放在新建的其他项目之前'apps.users',
]#2、中间件
MIDDLEWARE = ['django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','corsheaders.middleware.CorsMiddleware', #【配置drf的跨域】注意顺序'django.middleware.common.CommonMiddleware',# 'django.middleware.csrf.CsrfViewMiddleware', #【注销django】'django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware',
]#3、配置允许的跨域#允许携带cookies
CORS_ALLOW_CREDENTIALS = True #允许所有域名跨域,[有这个,就无需配置白名单]
CORS_ORIGIN_ALLOW_ALL = True #跨域允许的请求
CORS_ALLOW_METHODS = ('DELETE','GET','OPTIONS','PATCH','POST','PUT','VIEW',
)#跨域时,允许在请求头中携带的参数字段
CORS_ALLOW_HEADERS = ('accept','accept-encoding','authorization','content-type','dnt','origin','user-agent','x-csrftoken','x-requested-with',#配置允许自定义的参数在请求头中,如token数据'token'
)
4.2、注册drf
#使用新的Response需要使用到
INSTALLED_APPS = [.....'rest_framework',
]
4.3、配置认证
1、生成token的模块:util/token.py
import jwt
import datetime
# from django.conf import settings
from django.conf import settings
import timedef create_token(user_id:int, timeout=1*24*60*60):''':param user_id: 传递用户的id:param timeout: token有效时间,默认是一天:return:'''payload = {'user_id':user_id}salt = settings.SECRET_KEY #加密的盐# 构造headerheaders = {'type': 'jwt','alg': 'HS256'}now_datetime = time.time()payload['exp'] = now_datetime + timeout #token过期时间,时间戳# print(payload)token = jwt.encode(payload=payload, key=salt, algorithm="HS256", headers=headers).decode('utf-8')return token
2、解析token:util/authentication.py
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
import jwt
from django.conf import settings
from jwt import exceptions
from home import models #模型类class MyJWTAuthentication(BaseAuthentication):def authenticate(self,request):#获取tokentoken = request.META.get("HTTP_TOKNE") #从请求头中获取if not token:token = request.COOKIES.get('token') #从cookies中获取tokenif not token:msg = '没有携带token'raise AuthenticationFailed({'code': 400, 'msg': msg})'''1、切割2、解密第二段/判断过期3、验证第三段合法性'''#导入settings中的字符串做盐salt =settings.SECRET_KEYpayload = Nonemsg = Nonetry:payload = jwt.decode(token,salt,True)user = models.UserModel.objects.filter(id=payload.get('user_id')).first()return (user,token)#payload={'user_id':user.id}except exceptions.ExpiredSignatureError:msg='token过期了'raise AuthenticationFailed({'code':400,'msg':msg})except exceptions.DecodeError:msg='token认证失败'raise AuthenticationFailed({'code':400,'msg':msg})except exceptions.InvalidTokenError:msg='非法的token'raise AuthenticationFailed({'code':400,'msg':msg})
3、全局使用认证: settings.py
#配置drf的全局认证
REST_FRAMEWORK = {'DEFAULT_AUTHENTICATION_CLASSES': [#这个是我们自己写的认证类所在的位置'util.authentication.MyJWTAuthentication'],
}
4.4、配置权限
1、权限类:util/permission.py
from rest_framework.permissions import BasePermission
from home import modelsclass SuperAdminPermission(BasePermission):#重写has_permission方法message='当前用户没有管理员权限'def has_permission(self,request,view):#view是视图类的对象,拿到视图类的东西#不是超级用户不能访问,由于认证已经通过了,在request.user中就可以拿到用户user= request.userif user.role==1:return True#return True代表能够访问,负责不能访问else:return False
2、全局使用【基本不用,都是局部使用】
#全局使用:settings.py中配置,一般不会配置全局使用
REST_FRAMEWORK={'DEFAULT_PERMISSION_CLASSES':['util.permission.SuperAdminPermission'],
}
4.5、频率
1、频率类:util/throttle.py
# 这是一个对应ip进行限流的频率类
from rest_framework.throttling import SimpleRateThrottleclass IPThrottle(SimpleRateThrottle):# 在settings中配置频率时使用到的关键字,有scope来指定scope = 'IP'def get_cache_key(self, request, view):# 这里return什么,就以什么作为限制,这里限制ip,直接return ip就可以return request.META.get('REMOTE_ADDR')#可以在这里设置访问频率# def get_rate(self):# return '3/m'
2、使用
在settings.py中#全局使用
REST_FRAMEWORK = {'DEFAULT_AUTHENTICATION_CLASSES': [#这个是我们自己写的认证类所在的位置'util.authentication.MyJWTAuthentication'],#全局的使用的频率限制'DEFAULT_THROTTLE_CLASSES':('util.throttle.IPThrottle',),# 对于scope=IP的限制'DEFAULT_THROTTLE_RATES':{'IP':'3/m' #一个ip一分钟只能访问3次}
}#局部使用:在视图类开头设置
#setings中必须配置访问频率REST_FRAMEWORK={'DEFAULT_THROTTLE_RATES':{'IP':'3/m' #一个ip一分钟只能访问3次}
}
4.6、配置静态路由
1、开放static目录
#设置static的访问路由,系統默認開放了路由,無需再手動配置
STATIC_URL = '/static/'#对于以/static/开头的路由,从下面的设置的文件夹中查找
STATICFILES_DIRS=[os.path.join(BASE_DIR,'static')]
2、开放media目录:
#设置/media/ 路由,需要到根路由配置文件中开放该路由,系统没有默认开放
MEDIA_URL = '/media/'
#访问/media/路由时,从哪个目录下取资源
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
根urls.py
from django.conf import settings
from django.conf.urls.static import staticurlpatterns+=static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
五、登录注册功能
5.1、登录功能
home/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from util.permission import SuperAdminPermission
from django.contrib.auth.hashers import make_password, check_password
from . import serializers
from . import models
from util.token import create_token
# Create your views here.class LoginView(APIView):authentication_classes = []def post(self,request):username = request.data.get('username')password = request.data.get('password')user = models.UserModel.objects.filter(username=username).first()is_true = check_password(password,user.password)if is_true:token = create_token(user.pk)response = Response({'code':200,"msg":'登录成功'})response.set_cookie('token',token)return responseelse:return Response({'code':400,'msg':'用户名或密码错误'})
study_drf/urls.py
from django.contrib import admin
from django.urls import path,include
from home import views as home_viewsurlpatterns = [path('admin/', admin.site.urls),path('home/',include('home.urls')),path('register/', home_views.RegisterView.as_view(), name='register'),path('login/',home_views.LoginView.as_view(),name='login')
]
5.2、注册功能
home/serializers.py
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from home import modelsclass UserLoginModelSerializer(serializers.ModelSerializer):class Meta:model = models.UserModelfields = ['username','role','phoneNumber','realName','id','password']extra_kwargs = {'id':{'read_only':True,},'password':{'write_only':True}}def validate_phoneNumber(self,value):if len(value) !=11:raise ValidationError('手机号码验证失败')return valuedef validate_username(self,value):if len(value)>20:raise ValidationError('用户名长度过长')name = 'abqwertyuiopasdfghjklzxcvbnm1234567890'for key in value:if key not in name:raise ValidationError('用户名必须由小写字母数字组成')if models.UserModel.objects.filter(username=value).first():raise ValidationError('账户已经存在了,无法注册')return valuedef validate_role(self,value):if value not in [1,2,'1','2']:raise ValidationError('用户角色有问题')if models.UserModel.objects.filter(role=1).first() and value==1:raise ValidationError('管理员账户已经存在了')return valuedef create(self,validated_data):#拿到传递进来的requestrequest = self.context.get('request')try:models.UserModel.objects.create(validated_data)except Exception as e:raise ValidationError(str(e))return validated_data
home/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from util.permission import SuperAdminPermission
from django.contrib.auth.hashers import make_password, check_password
from . import serializers
from . import models
from util.token import create_tokenclass RegisterView(APIView):permission_classes = [SuperAdminPermission]def get(self,request):return Response({'code':100})def post(self,request):username = request.data.get('username')name = request.data.get('name')phoneNumber = request.data.get('phoneNumber')role = request.data.get('role')password = phoneNumber.strip()[-8:]password = make_password(password)data = {'username':username,'realName':name,'phoneNumber':phoneNumber,'role':role,'password':password}ser = serializers.UserLoginModelSerializer(data=data, context={'request': request})ser.is_valid(raise_exception=True)ser.save()return Response({'code':200,'method':'post'})
study_drf/urls.py
from django.contrib import admin
from django.urls import path,include
from home import views as home_viewsurlpatterns = [path('admin/', admin.site.urls),path('home/',include('home.urls')),path('register/', home_views.RegisterView.as_view(), name='register'),path('login/',home_views.LoginView.as_view(),name='login')
]