Python 中Django验证码功能的实现代码

  • Post category:Python

Sure! 首先我们需要了解 Django 如何生成验证码。 Django 提供了 django.contrib.auth.models 中的函数 make_password()check_password() 来加密和验证密码,但是 Django 没有提供直接生成验证码的函数。为此,我们需要借助第三方库 PillowCaptcha

以下是 Python 中 Django 验证码功能的实现代码的完整攻略:

1. 安装必要的依赖

  • Pillow: 用于生成图片和处理图片
  • captcha: 用于生成验证码

可以通过以下命令安装:

$ pip install Pillow captcha

2. 在 Django 项目中集成验证码

2.1 创建一个名为 captcha 应用

在 Django 项目中创建一个名为 captcha 的应用。

$ python manage.py startapp captcha

2.2 在 captcha 应用中创建 utils.py 模块

captcha 应用中创建一个名为 utils.py 的模块,并添加以下代码:

from io import BytesIO
from random import randint

from captcha.image import ImageCaptcha

def generate_code():
    """
    生成随机验证码并返回
    """
    code = ''
    for _ in range(4):
        code += str(randint(0, 9))
    return code

def generate_captcha_image(code):
    """
    生成验证码图片并返回二进制数据
    """
    image = ImageCaptcha(width=120, height=40)
    data = BytesIO()
    image.write(code, data)
    return data.getvalue()

2.3 在 captcha 应用中创建 views.py 模块

captcha 应用中创建一个名为 views.py 的模块,并添加以下代码:

from django.http import HttpResponse

from .utils import generate_code, generate_captcha_image

def generate_captcha(request):
    """
    生成验证码并返回二进制图片数据
    """
    code = generate_code()
    image_data = generate_captcha_image(code)
    response = HttpResponse(image_data, content_type='image/png')
    response['Content-Disposition'] = 'inline; filename=captcha.png'
    request.session['captcha'] = code
    return response

2.4 在 urls.py 中添加 captcha 的 URL

在项目的 urls.py 文件中添加以下 URL:

from django.urls import path

from captcha.views import generate_captcha

urlpatterns = [
    path('captcha/', generate_captcha, name='captcha'),
]

3. 在模板中显示验证码图片

在需要显示验证码的模板中添加以下代码:

<img src="{% url 'captcha' %}" alt="captcha">
<input type="text" name="captcha">

其中 url 标签会根据 URL 的 name 属性解析成正确的 URL,即 '/captcha/'

当用户提交表单时,你可以使用以下代码验证输入的验证码是否正确:

input_captcha = request.POST['captcha']
if input_captcha.lower() != request.session.get('captcha', '').lower():
    # 验证码不匹配

这里使用了 request.session.get() 来获取保存在 session 中的验证码,同时使用 lower() 将验证码转换为小写,以避免对大小写的敏感问题。

示例

示例 1:使用 Django 内置的 Form 和 Model 完成登录表单

假设我们有一个名为 user 的应用,我们的目标是实现一个登录表单页面,其中包含一个验证码字段,你可以按照以下步骤完成:

  1. 首先,在 user/forms.py 文件中创建一个名为 AuthenticationForm 的 Form:

“`python
from django import forms
from django.contrib.auth import authenticate

class AuthenticationForm(forms.Form):
username = forms.CharField(label=’用户名’)
password = forms.CharField(label=’密码’, widget=forms.PasswordInput)
captcha = forms.CharField(label=’验证码’)

   def clean(self):
       cleaned_data = super().clean()
       username = cleaned_data.get('username')
       password = cleaned_data.get('password')
       captcha = cleaned_data.get('captcha')

       user = authenticate(username=username, password=password)
       if user is None:
           raise forms.ValidationError('用户名或密码错误')

       if captcha.lower() != self.request.session.get('captcha', '').lower():
           raise forms.ValidationError('验证码错误')

       return cleaned_data

“`

这里我们使用 Django 内置的 Form 类作为基类,并添加了三个字段:用户名、密码以及验证码。在 clean() 方法中,我们验证了用户名和密码,并使用 self.request.session.get() 方法获取了保存在 session 中的验证码。最后,我们检验了验证码是否正确,如果验证码不正确,就会抛出一个 ValidationError 异常。

  1. 接下来,在 user/views.py 文件中创建一个名为 LoginView 的 View:

“`python
from django.contrib.auth.views import LoginView as BaseLoginView

from user.forms import AuthenticationForm

class LoginView(BaseLoginView):
form_class = AuthenticationForm
template_name = ‘user/login.html’
success_url = ‘/’
“`

这里我们使用了 Django 内置的 LoginView 类作为基类,并指定了 form_class 为我们刚刚创建的 AuthenticationForm Form。

  1. 在模板文件 user/login.html 中添加验证码部分的 HTML 代码:

“`html

{% csrf_token %}
{{ form.as_p }}
captcha


“`

在这个表单中,我们使用了 Django 内置的 {{ form.as_p }} 标签来将 Form 渲染成一个 HTML 表单,并添加了一个名为 captcha 的文本框以及一个显示验证码图片的 <img> 标签。

  1. 最后,在 urls.py 文件中添加 URL 并指定 View:

“`python
from django.urls import path

from user.views import LoginView

urlpatterns = [
path(‘login/’, LoginView.as_view(), name=’login’),
]
“`

现在,你的登录表单页面已经完成啦!你可以通过访问 http://localhost:8000/login/ 来测试。

示例 2:使用 Django REST framework 完成验证 API

假设你正在使用 Django REST framework 来创建一个 API,你想为这个 API 添加一个名为 /user/authenticate/ 的 URL,用于验证用户名、密码以及验证码是否正确。你可以按照以下步骤完成:

  1. 首先,在项目的 settings.py 文件中添加以下配置:

“`python
INSTALLED_APPS = [
# …
‘rest_framework’,
‘rest_framework.authtoken’,
‘captcha’,
]

REST_FRAMEWORK = {
‘DEFAULT_AUTHENTICATION_CLASSES’: [
‘rest_framework.authentication.TokenAuthentication’,
‘rest_framework.authentication.SessionAuthentication’,
],
‘DEFAULT_PERMISSION_CLASSES’: [
‘rest_framework.permissions.IsAuthenticated’,
],
}
“`

这里我们配置了 Django REST framework,使其支持 TokenAuthenticationSessionAuthentication 认证,并指定了默认的权限为 IsAuthenticated

  1. 接下来,在 user/views.py 文件中创建一个名为 AuthenticationAPIView 的 View:

“`python
from rest_framework import status
from rest_framework.authentication import TokenAuthentication, SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from captcha.utils import generate_code

class AuthenticationAPIView(APIView):
authentication_classes = [TokenAuthentication, SessionAuthentication]
permission_classes = [IsAuthenticated]

   def post(self, request):
       username = request.POST.get('username')
       password = request.POST.get('password')
       captcha = request.POST.get('captcha')

       user = authenticate(username=username, password=password)
       if user is None:
           return Response(data={'detail': '用户名或密码错误'}, status=status.HTTP_400_BAD_REQUEST)

       if captcha.lower() != request.session.get('captcha', '').lower():
           return Response(data={'detail': '验证码错误'}, status=status.HTTP_400_BAD_REQUEST)

       # 生成新的验证码
       request.session['captcha'] = generate_code()

       return Response(data={'detail': '认证成功'})

“`

在这里我们创建了一个名为 AuthenticationAPIView 的 View,并继承了 Django REST framework 的 APIView 类。在这个 API 中,我们接收了三个参数:usernamepasswordcaptcha,并分别进行了验证。如果这些信息验证不通过,我们就会返回一个 HTTP 400 BAD REQUEST 响应,表示请求无效。否则,我们将会生成一个新的验证码,并返回一个成功的响应。

  1. urls.py 文件中添加 URL 并指定 View:

“`python
from django.urls import path

from user.views import AuthenticationAPIView

urlpatterns = [
path(‘user/authenticate/’, AuthenticationAPIView.as_view(), name=’user_authenticate’),
]
“`

现在,你的验证 API 已经完成啦!你可以通过发送一个 POST 请求到 URL /user/authenticate/ 来测试。