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 time

def 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 #加密的盐
    # 构造header
    headers = {
        '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):
        #获取token
        token = request.META.get("HTTP_TOKNE") #从请求头中获取
        if not token:
            token = request.COOKIES.get('token') #从cookies中获取token
        if not token:
            msg = '没有携带token'
            raise AuthenticationFailed({'code': 400, 'msg': msg})
        '''
        1、切割
        2、解密第二段/判断过期
        3、验证第三段合法性
        '''
        #导入settings中的字符串做盐
        salt =settings.SECRET_KEY
        payload = None
        msg = None
        try:
            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 models

class  SuperAdminPermission(BasePermission):
    #重写has_permission方法
    message='当前用户没有管理员权限'
    def has_permission(self,request,view):
        #view是视图类的对象,拿到视图类的东西
        #不是超级用户不能访问,由于认证已经通过了,在request.user中就可以拿到用户
        user= request.user
        if 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 SimpleRateThrottle

class 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 static

urlpatterns = [ ]
#把media路由 加到路由列表中
urlpatterns+=static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)

#就可以通过 http://域名:端口/media  访问media文件夹中的数据了

五、登录注册功能

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 response
        else:
            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_views

urlpatterns = [
    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 models

class UserLoginModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.UserModel
        fields = ['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 value

    def 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 value

    def 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 value

    def create(self,validated_data):
        #拿到传递进来的request
        request = 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_token

class 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_views

urlpatterns = [
    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')
]

你可能感兴趣的:(django,django)