django登录源码与第三方登录验证源码
引言
这篇我想总结一下关于登录的一些方式,然后主要以三种方式实现登录验证,第一种是用原始验证码,第二种是用极验验证码,第三种是云通讯的短信验证码门下面就来介绍具体的实现步骤。
自制图片验证码
准备
自备一张验证码的图片,加一个文字板式文件。
后端实现
def login(request):
# 登陆是将信息输入进去
if request.method == "POST":
username = request.POST.get("username")
pwd = request.POST.get("password")
valid_code = request.POST.get("valid_code")
res = {"statu":0,"msg":None}
valid_str = request.session.get("valid_str")
print(valid_str)
# 验证验证码是否相同
if valid_code.upper() == valid_str.upper():
# 验证是否有这个用户
user = auth.authenticate(username=username,password=pwd)
# 通过认证,登陆成功,获取当前用户
if user:
res["msg"] = "/index/"
auth.login(request,user)
else:
res["status"] = 1
res["msg"]= "帐号或密码错误"
else:
res["status"] = 1
res["msg"] = "验证码错误"
return JsonResponse(res)
return render(request,"login.html")
def index(request):
return render(request, "index.html")
# 这里是生成图片验证码的地方
def get_valid_img(request):
from PIL import ImageDraw
from PIL import Image
import random
def random_color():
return random.randint(0,255),random.randint(0,255),random.randint(0,255)
img_obj = Image.new(
'RGB',
(220, 35),
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=random_color(), font=font_obj)
print("生成的验证码".center(120, "="))
valid_str="".join(tmp_list) # "xxxx"
print("valid_str",valid_str)
request.session["valid_str"]=valid_str
# 不需要在硬盘上保存文件,直接在内存中加载就可以
from io import BytesIO
io_obj = BytesIO()
# 将生成的图片数据保存在io对象中
img_obj.save(io_obj, "png")
# 从io对象里面取上一步保存的数据
data = io_obj.getvalue()
return HttpResponse(data)
前端实现
部分代码如下:
// 当input框获取焦点时将之前的错误清空
$("#username,#password").focus(function () {
// 将之前的错误清空
$(".login-error").text("");
});
// 点击验证码图片 刷新验证码
$("#valid-img").click(function () {
$(this)[0].src += "?";
})
演示效果
加干扰
如果觉得上面的图形验证码比较简单,还能加入干扰线,加大了反爬的难度,但也给用户增加了难度。
# 加干扰线
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=random_color())
使用极验验证码登录
极验后台下申请免费账户
这里登录成功后进入极验的后台,然后点击新增验证,名字还有域名可以随便填写,如果是单单拿来测试的话,比如说这里我就取名为测试自备,另外就是官方的SDK中也有提供相关的测试用例key和id,如果不想注册这个平台的账号,可以用我的测试用例。另外如果需要本篇全部的源码,可以加我QQ
后端实现
# 申明极验后台获取的测试账户
pc_geetest_id = "5e1e39abb2a23389a88a37ff03aa0d46"
pc_geetest_key = "047953424e4c2d9a83c5d754adedfd94"
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, "login.html")
# 处理极验 获取验证码的视图
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 index(request):
return render(request,"index.html")
前端实现
这里是部分核心代码,其实也就是极验的第三方提供的前端页面的核心代码:
$.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);
}
})
演示效果
这只是滑块的登录验证码的形式,极验验证码还有另外的三种方式,这些都可以从官网的登录demo中看到,在这里我们就只演示这种滑动的。
使用云通讯登录
登录云通讯控制台
这里面有五个参数需要考虑,另外在开发流程里面找到了python的demo,然后不同于极验,这个就需要另外去配置了,下面就是我的云通讯的一些配置,其中我是将token省略了,基本上这个还是保密的,因为一个手机号只能绑定一个。
后端实现
def send_code(request):
# 取到请求值中的内容
mobile = request.POST.get("mobile")
ret = {"errno": 0, "errmsg": None}
if not mobile:
ret["status"] = 1
ret["msg"] = "参数不全"
# 2. 校验手机号是正确
if not re.match("^1[3578][0-9]{9}$", mobile):
ret["status"] = 1
ret["msg"] = "提示手机号不正确"
user = UserInfo.objects.filter(telephone=mobile).first()
if not user:
ret["status"] = 1
ret["msg"] = "没有该用户"
# 5. 生成发送短信的内容并发送短信
result = random.randint(0, 999999)
sms_code = "%06d" % result
result = CCP().send_template_sms(mobile, [sms_code, 300 / 60], "1")
# 6. redis中保存短信验证码内容
global redis_store
redis_store = StrictRedis(host="127.0.0.1",
port=6379,
db=9,
decode_responses=True
)
try:
redis_store.set("SMS_" + mobile, sms_code, 300)
except Exception as e:
ret["status"] = 1
ret["msg"] = "保存短信验证码失败"
# 7. 返回发送成功的响应
return JsonResponse(ret)
前端实现
暂时无,这里留个坑位,以待以后回来填。
云通讯的方式对我来说有些不友好,首先是问题一大堆。注册这个平台的时候,验证码图片换了十多张才勉强对了一遍,是真看不清。。。另外就是注册完后,参数有点多,还有就是沙箱环境问题,这里的坑是,如果不改的话程序都跑不出来。。。必须要生产环境,另外还有一大堆bug,留待以后吧。