Django之前后端分离自定义token认证

1. settings.py

from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

SECRET_KEY = 'django-insecure-7jzbod!!(2p#zzimb$_=azn&%wlm2uvtp&=)ijx1&zmtsr^0av'

DEBUG = True

ALLOWED_HOSTS = ['*']

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app.apps.AppConfig',
    'corsheaders',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    # 添加跨域处理中间件
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'app.middleware.TokenAuthenticationMiddleware',
]

# 跨域处理
CORS_ALLOW_CREDENTIALS = True  # 允许携带身份凭证(如 Cookie)
CORS_ORIGIN_ALLOW_ALL = True  # 设置为 True 表示允许所有跨域请求,不推荐在生产环境使用
CORS_ALLOW_ALL_ORIGINS = True  # 允许所有 域名/IP 跨域
# CORS_ORIGIN_WHITELIST = ('http://127.0.0.1:*',) # 配置可跨域访问的 域名/IP
CORS_ALLOW_METHODS = ('*',)  # 允许的 HTTP 请求方法 * 表示允许全部请求方法

# CORS_ALLOW_METHODS = (
#     'GET',
#     'POST',
#     'PUT',
#     'PATCH',
#     'DELETE',
#     'OPTIONS',
# )  # 允许的 HTTP 请求方法

CORS_ALLOW_HEADERS = (
    'XMLHttpRequest',
    'X_FILENAME',
    'accept-encoding',
    'authorization',
    'content-type',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'x-requested-with',
)  # 允许的请求头

# CORS_EXPOSE_HEADERS = ()  # 允许前端访问的响应头

ROOT_URLCONF = 'rbacProject.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates']
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'rbacProject.wsgi.application'


DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'rbac_db',
        'HOST': 'localhost',
        'PORT': '3306',
        'USER': 'root',
        'PASSWORD': 'root',
        'OPTIONS': {
            'charset': 'utf8mb4',
            'init_command': "SET time_zone='+8:00'",
        },
    }
}


AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_TZ = True


STATIC_URL = 'static/'


DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'


'''jwt配置'''
#私钥
JWT_SECRET_KEY='8UhyuegyPYOFsqTPTX9FgLga4iYkssssLgggggggNQVn9jsasdhfaeYJXiS'
#TOKEN内容密钥   AES-128-ECB   偏移量0
# TOKEN_AES128_KEY = 'o0ubx1kB2V8aGq8L'

'''统一错误响应'''
#请求失败(默认)返回内容
# RES_DEFAULT_CONTENT = {'code':'9','data':{},'msg':'请求错误'}

'''请求前缀'''
#请求接口前缀  需要携带 /
# API_REQUEST_PREFIX = '/api'

'''安全认证相关'''
#无需token认证白名单列表
# NOT_TOKEN_PROCESS_ROUTE_LIST = [API_REQUEST_PREFIX+'/login']
NOT_TOKEN_PROCESS_ROUTE_LIST = ['/login','/register']
#IP白名单 长度大于0 表示启用
IP_ADDRESS_WHITE_LIST = []
#IP黑名单 长度大于0 表示启用
IP_ADDRESS_BLACK_LIST = []

2. urls.py

from django.contrib import admin
from django.conf.urls import url
from app.views import *

urlpatterns = [
    url(r'^admin/', admin.site.urls),

    url(r'^login/', login),
    url(r'^logout/', logout),
    url(r'^register/', register),
    url(r'^info/', get_info),
    url(r'^paging/', paging),
]

3. result.py

from django.http import JsonResponse

# 封装返回json响应结果类
class Result:
    @classmethod
    def success(self, data=None, message="操作成功"):
        return JsonResponse({
            "code": 0,
            "success": True,
            "data": data,
            "message": message
        })

    @classmethod
    def error(self):
        return JsonResponse({
            "code": -1,
            "success": False,
            "data": None,
            "message": "请求错误!"
        })

    @classmethod
    def fail(self, message="操作失败"):
        return JsonResponse({
            "code": 1,
            "success": False,
            "data": None,
            "message": message
        })

4. baseModelMixin

import datetime

# 模型对象转成json对象基类
class BaseModelMixin:
    def to_json(self, exclude=None):
        fields = [f.name for f in self._meta.fields]
        if exclude:
            fields = [f for f in fields if f not in exclude]
        data = {}
        for f in fields:
            value = getattr(self, f)
            if isinstance(value, datetime.datetime):
                value = value.strftime('%Y-%m-%d %H:%M:%S')
            data[f] = value
        return data

5. models.py

import datetime
from django.db import models
from utils.baseModelMixin import BaseModelMixin
import jwt
from rbacProject.settings import JWT_SECRET_KEY

# Create your models here.
class User(models.Model, BaseModelMixin):
    username = models.CharField(max_length=30,unique=True,verbose_name='用户名')
    password = models.CharField(max_length=255,verbose_name='密码')
    email = models.EmailField(verbose_name='邮箱')
    mobile = models.CharField(max_length=11,unique=True,verbose_name='手机号码')
    create_time = models.DateTimeField(auto_now_add=True,null=True,verbose_name='创建时间')
    update_time = models.DateTimeField(auto_now=True,null=True,verbose_name='更新时间')
    def __str__(self):
        return self.username

    @property
    def token(self):
        return self._generate_jwt_token()

    # 生成token
    def _generate_jwt_token(self):
        token = jwt.encode({
            'exp': datetime.datetime.now(tz=datetime.timezone.utc) + datetime.timedelta(seconds=1*60*60*24),
            'iat': datetime.datetime.now(),
            'data': {
                'username': self.username,
                'user_id': self.id
            }
        }, JWT_SECRET_KEY, algorithm='HS256')

        return token.decode('utf-8')  # 将令牌转换为字符串类型

6. views.py

from django.contrib.auth import logout as auth_logout
from django.core.paginator import Paginator
from django.contrib.auth.hashers import make_password, check_password
from utils.result import Result
import json
from app.models import *
# Create your views here.

def login(request):
    if request.method == 'POST':
        try:
            req_data = json.loads(request.body)
            username = req_data['username']
            password = req_data['password']
            user = User.objects.get(username=username)

            if check_password(password, user.password):  # 使用 check_password 函数验证密码
                token = user.token
                token_ = {"token": token}
                return Result.success(token_,"登录成功!")
            else:
                return Result.fail("用户名或密码错误!")
        except (KeyError, User.DoesNotExist):
            return Result.fail("用户名或密码错误!")

    return Result.error()

def register(request):
    if request.method == 'POST':
        # 从请求中获取注册信息
        req_data = json.loads(request.body)
        username = req_data['username']
        password = req_data['password']
        email = req_data['email']
        mobile = req_data['mobile']

        try:
            # 创建用户对象并保存到数据库
            hashed_password = make_password(password)  # 对密码进行加密
            user = User(username=username, password=hashed_password, email=email, mobile=mobile)
            user.save()
            # 返回注册成功的响应
            return Result.success("注册成功!")
        except Exception as e:
            # 处理注册过程中的异常情况
            return Result.fail("注册失败!")

        # 返回请求方式不允许的响应
    return Result.error()


def logout(request):
    if request.method == 'POST':
        auth_logout(request)  # 删除会话信息
        # 返回成功响应
        return Result.success("退出登录成功!")
    return Result.error()

def get_info(request):
    if request.method == 'GET':
        user = request.user  # 通过中间件已经验证过的用户对象
        data = user.to_json(exclude=["password"])
        return Result.success(data,"查询成功")
    return Result.error()


def paging(request):
    if request.method == 'POST':
        # 获取前端传来的参数
        req_data = json.loads(request.body)
        per_page = req_data['per_page']
        page = req_data['page']
        users = User.objects.all()
        paginator = Paginator(users, per_page)
        page_data = [user.to_json(exclude=['password']) for user in paginator.page(page).object_list]
        total_page = paginator.num_pages
        total_count = paginator.count
        data = {"records": page_data, "total_page":total_page, "total_count":total_count}
        return Result.success(data)
    return Result.error()

7. middleware.py

import jwt
from django.utils.deprecation import MiddlewareMixin
from app.models import User
from utils.result import Result
from rbacProject.settings import JWT_SECRET_KEY,NOT_TOKEN_PROCESS_ROUTE_LIST

'''
token认证中间件
'''

class TokenAuthenticationMiddleware(MiddlewareMixin):
    def process_request(self, request):
        # 检查请求的 URL 是否在白名单中,如果是,则跳过认证
        if any([request.path.startswith(url) for url in NOT_TOKEN_PROCESS_ROUTE_LIST]):
            return None

        # 检查请求头中是否有 HTTP_AUTHORIZATION
        if 'HTTP_AUTHORIZATION' not in request.META:
            return Result.fail("未提供身份验证令牌!")

        # 进行token认证
        auth_header = request.META['HTTP_AUTHORIZATION']
        try:
            prefix, token = auth_header.split(' ')
            if prefix == 'Bearer':
                decoded_token = jwt.decode(token, JWT_SECRET_KEY, algorithms=['HS256'])
                request.user = User.objects.get(id=decoded_token['data']['user_id'])
        except jwt.exceptions.ExpiredSignatureError:
            return Result.fail("token认证过期!")
        except (ValueError, jwt.ExpiredSignatureError, jwt.InvalidTokenError, User.DoesNotExist):
            return Result.fail("token认证无效!")

        # token认证成功,放行
        return None

  • 11
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值