一、验证码实现

  1. 方式一:自己定义验证码
# 获取随机颜色的函数
def get_random_color():
    return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)

# 生成一个图片对象
img_obj = Image.new(
    'RGB',
    (220, 35),
    get_random_color()
)
# 在生成的图片上写字符
# 生成一个图片画笔对象
draw_obj = ImageDraw.Draw(img_obj)
# 加载字体文件, 得到一个字体对象
font_obj = ImageFont.truetype("static/font/kumo.ttf", 28)
# 开始生成随机字符串并且写到图片上
tmp_list = []
for i in range(5):
    u = chr(random.randint(65, 90))  # 生成大写字母
    l = chr(random.randint(97, 122))  # 生成小写字母
    n = str(random.randint(0, 9))  # 生成数字,注意要转换成字符串类型

    tmp = random.choice([u, l, n])
    tmp_list.append(tmp)
    draw_obj.text((20+40*i, 0), tmp, fill=get_random_color(), font=font_obj)

print("".join(tmp_list))
print("生成的验证码".center(120, "="))
# 不能保存到全局变量
# global VALID_CODE
# VALID_CODE = "".join(tmp_list)

# 保存到session
request.session["valid_code"] = "".join(tmp_list)
# 加干扰线
# width = 220  # 图片宽度(防止越界)
# height = 35
# for i in range(5):
#     x1 = random.randint(0, width)
#     x2 = random.randint(0, width)
#     y1 = random.randint(0, height)
#     y2 = random.randint(0, height)
#     draw_obj.line((x1, y1, x2, y2), fill=get_random_color())
#
# # 加干扰点
# for i in range(40):
#     draw_obj.point((random.randint(0, width), random.randint(0, height)), fill=get_random_color())
#     x = random.randint(0, width)
#     y = random.randint(0, height)
#     draw_obj.arc((x, y, x+4, y+4), 0, 90, fill=get_random_color())

# 将生成的图片保存在磁盘上
# with open("s10.png", "wb") as f:
#     img_obj.save(f, "png")
# # 把刚才生成的图片返回给页面
# with open("s10.png", "rb") as f:
#     data = f.read()

# 不需要在硬盘上保存文件,直接在内存中加载就可以
from io import BytesIO
io_obj = BytesIO()
# 将生成的图片数据保存在io对象中
img_obj.save(io_obj, "png")
# 从io对象里面取上一步保存的数据
data = io_obj.getvalue()
return HttpResponse(data)

自己生成验证码的登录:

def login(request):
    # if request.is_ajax():  # 如果是AJAX请求
    if request.method == "POST":
        # 初始化一个给AJAX返回的数据
        ret = {"status": 0, "msg": ""}
        # 从提交过来的数据中 取到用户名和密码
        username = request.POST.get("username")
        pwd = request.POST.get("password")
        valid_code = request.POST.get("valid_code")  # 获取用户填写的验证码
        print(valid_code)
        print("用户输入的验证码".center(120, "="))
        if valid_code and valid_code.upper() == request.session.get("valid_code", "").upper():
            # 验证码正确
            # 利用auth模块做用户名和密码的校验
            user = auth.authenticate(username=username, password=pwd)
            if user:
                # 用户名密码正确
                # 给用户做登录
                auth.login(request, user)
                ret["msg"] = "/index/"
            else:
                # 用户名密码错误
                ret["status"] = 1
                ret["msg"] = "用户名或密码错误!"
        else:
            ret["status"] = 1
            ret["msg"] = "验证码错误"

        return JsonResponse(ret)
    return render(request, "login.html")

2、方式二:极客验证码

获取视图

# 请在官网申请ID使用,示例ID不可使用
pc_geetest_id = "b46d1900d0a894591916ea94ea91bd2c"
pc_geetest_key = "36fc3fe98530eea08dfc6ce76e3d24c4"


# 处理极验 获取验证码的视图
def get_geetest(request):
    user_id = 'test'
    gt = GeetestLib(pc_geetest_id, pc_geetest_key)
    status = gt.pre_process(user_id)
    request.session[gt.GT_STATUS_SESSION_KEY] = status
    request.session["user_id"] = user_id
    response_str = gt.get_response_str()
    return HttpResponse(response_str)

使用极验滑动验证码的登录

def login(request):
    # if request.is_ajax():  # 如果是AJAX请求
    if request.method == "POST":
        # 初始化一个给AJAX返回的数据
        ret = {"status": 0, "msg": ""}
        # 从提交过来的数据中 取到用户名和密码
        username = request.POST.get("username")
        pwd = request.POST.get("password")
        # 获取极验 滑动验证码相关的参数
        gt = GeetestLib(pc_geetest_id, pc_geetest_key)
        challenge = request.POST.get(gt.FN_CHALLENGE, '')
        validate = request.POST.get(gt.FN_VALIDATE, '')
        seccode = request.POST.get(gt.FN_SECCODE, '')
        status = request.session[gt.GT_STATUS_SESSION_KEY]
        user_id = request.session["user_id"]

        if status:
            result = gt.success_validate(challenge, validate, seccode, user_id)
        else:
            result = gt.failback_validate(challenge, validate, seccode)
        if result:
            # 验证码正确
            # 利用auth模块做用户名和密码的校验
            user = auth.authenticate(username=username, password=pwd)
            if user:
                # 用户名密码正确
                # 给用户做登录
                auth.login(request, user)
                ret["msg"] = "/index/"
            else:
                # 用户名密码错误
                ret["status"] = 1
                ret["msg"] = "用户名或密码错误!"
        else:
            ret["status"] = 1
            ret["msg"] = "验证码错误"

        return JsonResponse(ret)
    return render(request, "login2.html")

js代码

// 极验 发送登录数据的
    var handlerPopup = function (captchaObj) {
        // 成功的回调
        captchaObj.onSuccess(function () {
            var validate = captchaObj.getValidate();
            // 1. 取到用户填写的用户名和密码 -> 取input框的值
            var username = $("#username").val();
            var password = $("#password").val();
            $.ajax({
                url: "/login/", // 进行二次验证
                type: "post",
                dataType: "json",
                data: {
                    username: username,
                    password: password,
                    csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(),
                    geetest_challenge: validate.geetest_challenge,
                    geetest_validate: validate.geetest_validate,
                    geetest_seccode: validate.geetest_seccode
                },
                success: function (data) {
                    console.log(data);
                    if (data.status) {
                        // 有错误,在页面上提示
                        $(".login-error").text(data.msg);
                    } else {
                        // 登陆成功
                        location.href = data.msg;
                    }
                }
            });
        });

         $("#login-button").click(function () {
            captchaObj.show();
        });
        // 将验证码加到id为captcha的元素里
        captchaObj.appendTo("#popup-captcha");
        // 更多接口参考:http://www.geetest.com/install/sections/idx-client-sdk.html
    };
    // 当input框获取焦点时将之前的错误清空
    $("#username,#password").focus(function () {
        // 将之前的错误清空
        $(".login-error").text("");
    });

    // 验证开始需要向网站主后台获取id,challenge,success(是否启用failback)
    $.ajax({
        url: "/pc-geetest/register?t=" + (new Date()).getTime(), // 加随机数防止缓存
        type: "get",
        dataType: "json",
        success: function (data) {
            // 使用initGeetest接口
            // 参数1:配置参数
            // 参数2:回调,回调的第一个参数验证码对象,之后可以使用它做appendTo之类的事件
            initGeetest({
                gt: data.gt,
                challenge: data.challenge,
                product: "popup", // 产品形式,包括:float,embed,popup。注意只对PC版验证码有效
                offline: !data.success // 表示用户后台检测极验服务器是否宕机,一般不需要关注
                // 更多配置参数请参见:http://www.geetest.com/install/sections/idx-client-sdk.html#config
            }, handlerPopup);
        }
    })

二、form表单

from django import forms
from django.core.exceptions import ValidationError
from blog import models


# 定义一个注册的form类
class RegForm(forms.Form):
    username = forms.CharField(
        max_length=16,
        label="用户名",
        error_messages={
            "max_length": "用户名最长16位",
            "required": "用户名不能为空",
        },

        widget=forms.widgets.TextInput(
            attrs={"class": "form-control"},
        )
    )

    password = forms.CharField(
        min_length=6,
        label="密码",
        widget=forms.widgets.PasswordInput(
            attrs={"class": "form-control"},
            render_value=True,
        ),
        error_messages={
            "min_length": "密码至少要6位!",
            "required": "密码不能为空",
        }
    )

    re_password = forms.CharField(
        min_length=6,
        label="确认密码",
        widget=forms.widgets.PasswordInput(
            attrs={"class": "form-control"},
            render_value=True,
        ),
        error_messages={
            "min_length": "确认密码至少要6位!",
            "required": "确认密码不能为空",
        }
    )

    email = forms.EmailField(
        label="邮箱",
        widget=forms.widgets.EmailInput(
            attrs={"class": "form-control"},

        ),
        error_messages={
            "invalid": "邮箱格式不正确!",
            "required": "邮箱不能为空",
        }
    )

    # 重写username字段的局部钩子
    def clean_username(self):
        username = self.cleaned_data.get("username")
        is_exist = models.UserInfo.objects.filter(username=username)
        if is_exist:
            # 表示用户名已注册
            self.add_error("username", ValidationError("用户名已存在"))
        else:
            return username

    # 重写email字段的局部钩子
    def clean_email(self):
        email = self.cleaned_data.get("email")
        is_exist = models.UserInfo.objects.filter(email=email)
        if is_exist:
            # 表示邮箱已注册
            self.add_error("email", ValidationError("邮箱已被注册"))
        else:
            return email

    # 重写全局的钩子函数,对确认密码做校验
    def clean(self):
        password = self.cleaned_data.get("password")
        re_password = self.cleaned_data.get("re_password")

        if re_password and re_password != password:
            self.add_error("re_password", ValidationError("两次密码不一致"))

        else:

            return self.cleaned_data

钩子函数:依赖于:

python后端验证码 python写验证码_用户名


这个校验过程会经过对应的局部钩子函数,比如登录或注册校验可以使用

注册示例;

def register(request):
    if request.method == "POST":
        ret = {'status':0,'msg':''}
        form_obj = RgForms(request.POST)
        # 帮我做校验
        if form_obj.is_valid():
            # 校验通过去数据库健一个新的数据
            form_obj.cleaned_data.pop("repassword")
            img_ava = request.FILES.get('img-ava')
            models.UserInfo.objects.create_user(**form_obj.cleaned_data,avatar=img_ava)
            ret['msg'] = '/index/'
            return JsonResponse(ret)
        else:
            ret['status'] = 1
            ret['msg'] = form_obj.errors
            return JsonResponse(ret)
    form_obj = RgForms()
    return render(request,'register.html',{'form_obj':form_obj})