探索前后端分离架构下的验证码实现方法

随着对小程序开发的学习,我选择了使用uniapp作为前端框架,并发现了一个名为django-ninja的新型后端包。在本文中,我将详细记录我实现的功能块以及相关的过程

整体流程分析

1. 前端发送获取验证码的请求(GET)。
2. 后端生成验证码图片和唯一标识符(UUID)。
3. 将UUID和验证码文本进行存储。
4. 返回包含验证码图片和UUID的响应给前端。
5. 前端接收到响应后,展示验证码图片,并将UUID存储在本地。
6. 当用户输入验证码时,前端将UUID和验证码文本发送到后端进行比对。
7. 后端根据UUID检索存储的验证码文本,并与用户输入进行比对。
8. 如果比对成功,后端删除存储的验证码信息。

后端验证码实现

为了实现验证码功能,我选择使用了django-simple-captcha这个包,它提供了验证码生成和存储的功能。

django-simple-captcha

1. 首先,我们需要下载并安装该包:
pip install  django-simple-captcha
2. 接下来,在项目的设置文件中注册该应用:
# settings.py
INSTALLED_APPS = [
...
    captcha,
]
3. 在设置文件中,我们还需要配置一些基本的验证码参数,例如验证码图片大小、字符个数、超时时间、字体大小、前景色、背景色等。你可以根据自己的需求进行配置。
# ================================================= #
# **************** 验证码配置  ******************* #
# ================================================= #
CAPTCHA_IMAGE_SIZE = (160, 60)  # 设置 captcha 图片大小
CAPTCHA_LENGTH = 4  # 字符个数
CAPTCHA_TIMEOUT = 1  # 超时(minutes)
CAPTCHA_OUTPUT_FORMAT = "%(image)s %(text_field)s %(hidden_field)s "
CAPTCHA_FONT_SIZE = 40  # 字体大小
CAPTCHA_FOREGROUND_COLOR = "#64DAAA"  # 前景色
CAPTCHA_BACKGROUND_COLOR = "#F5F7F4"  # 背景色
CAPTCHA_NOISE_FUNCTIONS = (
    "captcha.helpers.noise_arcs",  # 线
    # "captcha.helpers.noise_dots",  # 点
)
# CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.random_char_challenge' #字母验证码
CAPTCHA_CHALLENGE_FUNCT = "captcha.helpers.math_challenge"  # 加减乘除验证码
4. 然后,我们需要生成相应的数据库表:
python manage.py migrate
去看一下生成的表,就五个字段,还是很好理解的,`expiration`就是过期时间了

image.png

现在,我们已经可以生成验证码了。接下来,让我们来看一下如何在前端获取验证码。

首先,让我们查阅一下官方文档。嗯…官方文档可能不是很友好,不如我们直接看一下源代码。

在将该应用配置到Django项目中时,我们需要设置一个路由:
path('captcha/', include('captcha.urls'))

从路由captcha.urls开始看

urlpatterns = [
    re_path(
        r"image/(?P<key>\w+)/$",
        views.captcha_image,
        name="captcha-image",
        kwargs={"scale": 1},
    ),
    re_path(
        r"image/(?P<key>\w+)@2/$",
        views.captcha_image,
        name="captcha-image-2x",
        kwargs={"scale": 2},
    ),
    re_path(r"audio/(?P<key>\w+).wav$", views.captcha_audio, name="captcha-audio"),
    re_path(r"refresh/$", views.captcha_refresh, name="captcha-refresh"),
]
通过查看captcha.urls的源代码,可以找到获取验证码图片、音频和刷新验证码的路由。

找到后,postman试下接口,直接返回404,6,那只能继续看下源码

def captcha_refresh(request):
    """Return json with new captcha for ajax refresh request"""
    if not request.headers.get("x-requested-with") == "XMLHttpRequest":
        raise Http404

    new_key = CaptchaStore.pick()
    to_json_response = {
        "key": new_key,
        "image_url": captcha_image_url(new_key),
        "audio_url": captcha_audio_url(new_key)
        if settings.CAPTCHA_FLITE_PATH
        else None,
    }
    return HttpResponse(json.dumps(to_json_response), content_type="application/json")

然后看到了这个

if not request.headers.get("x-requested-with") == "XMLHttpRequest":
        raise Http404

??? 牛逼

那没办法了,重新封装一个吧

既然如此,那我们就重新封装一个吧

下面是我的封装
获取新验证码、验证用户输入以及处理超时和错误情况的功能。
#     -*-    coding: utf-8   -*-
# @File     :       captcah_util.py
# @Time     :       2023/7/17 12:02
# Author    :       摸鱼呀阿凡
# Contact   :       f2095522823@gmail.com
# License   :       MIT LICENSE
import base64

from captcha.conf import settings
from captcha.models import CaptchaStore
from captcha.helpers import captcha_audio_url, captcha_image_url
from captcha.views import captcha_image
from django.utils import timezone


class CaptchaItem_url:
    def __init__(self, key, image_url, audio_url):
        self.key = key
        self.image_url = image_url
        self.audio_url = audio_url


class CaptchaItem_count:
    def __init__(self, key, image_conte):
        self.key = key
        self.image_conte = image_conte


def refresh(request, choose: int = 1) -> CaptchaItem_url or CaptchaItem_count:
    """
    获取新的验证码
    :param request
    :param choose 1 or 2
    :return CaptchaItem_url or CaptchaItem_count
    """

    key = CaptchaStore.pick()
    if choose == 1:
        return CaptchaItem_url(
            key,
            captcha_image_url(key),
            captcha_audio_url(key) if settings.CAPTCHA_FLITE_PATH else None,
        )
    elif choose == 2:
        return CaptchaItem_count(
            key,
            base64.b64encode(captcha_image(request, key).content).decode("utf-8")
        )


def verify(key: str, code: str) -> str:
    """
    检查输入的验证码是否正确并处理超时和错误情况
    """
    current_time = timezone.now()
    try:
        captcha = CaptchaStore.objects.get(response=code, hashkey=key)

        # 检查验证码是否超时
        if captcha.expiration < current_time:
            captcha.delete()
            return '超时'  # 返回超时提示

        # 验证码正确,删除记录并返回成功
        captcha.delete()
        return '成功'  # 返回成功提示

    except CaptchaStore.DoesNotExist:
        # 清理过期的验证码记录
        CaptchaStore.remove_expired()
        return '错误'  # 返回错误提示

在api.py下实现验证码获取
#     -*-    coding: utf-8   -*-
# @File     :       login.py
# @Time     :       2023/7/17 9:42
# Author    :       摸鱼呀阿凡
# Contact   :       f2095522823@gmail.com
# License   :       MIT LICENSE
import json

from django.http import HttpResponse

from ninja import Router

from wechatapp.utlis.captcah_util import refresh

router = Router()


@router.get('/captchaImage', auth=None)
def get_captcha(request):
    data = {}
    new_captcha = refresh(request, 2)
    # 将图片转换为base64
    data = {
        "msg": "操作成功",
        "img": new_captcha.image_conte,
        "code": 200,
        "captchaEnabled": True,
        "uuid": new_captcha.key,
    }

    return HttpResponse(json.dumps(data), content_type="application/json")

后端登录鉴权

JWT

这里我使用的是 simple jwt

pip install simple jwt

这个包就三个用法(应该):编码,解码,制作
编码:

from simplejwt import make
token = make('secret', {'my_payload': 'some_data'}, 'HS256', issuer='acme', valid_to=1234567)
# eyJ0eXBlIjogIkpXVCIsICJhbGciOiAiSFMyNTYifQ.eyJteV9wYXlsb2FkIjogInNvbWVfZGF0YSIsICJpc3MiOiAiYWNtZSIsICJleHAiOiAxMjM0NTY3fQ.Nr5IADzsOhlzjxnghquBrRwewg10srDHu__-HN7GGGA
参数名类型默认值描述
secretstr_用于创建token的一串你自己写的字符串
payloaddict_token中想要包含的数据
algintHS256创建token的算法

自制:

from simplejwt import make
token = make('secret', {'my_payload': 'some_data'}, 'HS256', issuer='acme', valid_to=1234567)
# eyJ0eXBlIjogIkpXVCIsICJhbGciOiAiSFMyNTYifQ.eyJteV9wYXlsb2FkIjogInNvbWVfZGF0YSIsICJpc3MiOiAiYWNtZSIsICJleHAiOiAxMjM0NTY3fQ.Nr5IADzsOhlzjxnghquBrRwewg10srDHu__-HN7GGGA

参数名类型默认值描述
secretstr_用于创建 token 的一串你自己写的字符串
payloaddict_token 中想要包含的数据
algintHS256创建token 的算法
issuerstrNonetoken 的发行者
subjectstrNonetoken 的主题
audiencestrNonetoken 的受众
valid_tointNonetoken 的到期日期(时间戳
valid_fromintNonetoken 有效的日期(时间戳
issued_atintNonetoken 的发行日期(时间戳)
idstrNonetoken 的 ID

解码

from simplejwt import encode, decode
token = encode('secret', {'my_payload': 'some_data'}, 'HS256')
payload = decode('secret', token, 'HS256')
# {'my_payload': 'some_data'}
参数名类型默认值描述
secretstr_用于解码 token 的字符串
payloaddict_要解码的 token
algintHS256用于创建 token 的算法

以上就是关于前后端分离架构下验证码实现和后端登录鉴权的一些简要介绍和代码示例。希望对你有所帮助!如果你还有其他问题或需要进一步的解释,请随时提问。

一些官网链接

django-ninja
uni-app

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值