Эх, внезапный обмен напомнил мне, что я задержался надолго, и не было сделано осуществление различных проверок. Я воспользовался этой возможностью, чтобы сделать это Разделено на три части: подтверждение по электронной почте, подтверждение по SMS, код подтверждения с изображением.
Подтверждение по элетронной почте
Этот раздел является основным справочником по классической книге «Книги о собаках». Идея состоит в том, чтобы сгенерировать токен с помощью веб-подписи JSON на основе некоторой информации о пользователе, а затем отправить электронное письмо для проверки.Классическая идея Функции генерации и проверки загружаются в модель.
его опасная китайская документация
Вот несколько способов подписать
генерация и проверка токена TimedJSONWebSignatureSerializer, глядя на значение этого поверхностного слова, можно увидеть, что здесь в сериализацию добавляется текущее время Это также является основой для установки времени истечения срока действия. Проверьте его опасный исходный код, чтобы увидеть конкретный метод шифрования.
from itsdangerous import (TimedJSONWebSignatureSerializer as Serializer, BadSignature, SignatureExpired)
...
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer,primary_key=True)
name=db.Column(db.String(64),unique=True,index=True)
def genter_auth_token(self,expiration=300): #设置有效期
s=Serializer(current_app.config['SECRET_KEY'],expires_in=expiration)
return s.dumps({'code':self.name}) #将用户名当作签名对象
@staticmethod
def verify_auth_token(token):
s=Serializer(current_app.config['SECRET_KEY'])
try:
data=s.loads(token) #加载数据
except BadSignature:
return None
except SignatureExpired:
return None
return data
При этом сигнатурный метод класса itdangerous здесь может получить соль Документация описывает, что делает соль следующим образом:
Опасная соль создана совсем для другой цели. вы можете думать об этом как о пространстве имен Предположим, вы хотите подписать две ссылки. В вашей системе есть ссылка для активации учетной записи пользователя, а у вас есть ссылка на обновление для обновления учетной записи пользователя до платного пользователя, обе ссылки отправляются по электронной почте. В обоих случаях, если вы подписываетесь с идентификатором пользователя, этот пользователь может повторно использовать переменную часть URL-адреса при активации и обновлении учетной записи. Теперь вы можете добавить дополнительную информацию (например, о намерении обновить или активировать), где вы подписываетесь, но вы также можете использовать другую соль.
То есть только сериализаторы, использующие одну и ту же соль, могут успешно загрузить значение.
def genter_auth_token(self,expiration=300):
s=Serializer(current_app.config['SECRET_KEY'],salt='activate-salt',expires_in=expiration)
return s.dumps({'code':self.name})
@staticmethod
def verify_auth_token(token):
s=Serializer(current_app.config['SECRET_KEY'],salt='activate-salt')
Код подтверждения изображения
Этот код проверки может напрямую вызывать интеллектуальную проверку некоторых платформ или использовать другую. Другой может быть более традиционная идея, то есть изображение водяного знака, созданное вами самостоятельно, сохраните проверочный код. Существуют соответствующие методы работы с изображениями как в python, так и в php, вот
Процесс заключается в создании произвольных чисел, сохранении и добавлении водяных знаков изображения.
Здесь должна использоваться мощная библиотека обработки изображений Python PIL, которая использует Добавьте линии, фильтры и т. д., чтобы усилить помехи. Ниже приведен полный код, я добавил комментарии, где я должен комментировать Перед просмотром кода лучше внимательно изучить официальную документацию PIL и некоторые основные понятия. Некоторые из сообщений блога, на которые я ссылался, также размещены в конце текста.
#!/usr/bin/env python
#coding=utf-8
import os
import random
from flask import Flask,send_from_directory
from PIL import Image,ImageFont,ImageDraw,ImageFilter
app=Flask(__name__)
app.debug=True
class picture:
def __init__(self):
self.size = (240,60)
self.mode="RGB"
self.color="white"
self.font = ImageFont.truetype("C:\Windows\Fonts\Arial.ttf", 36) #设置字体大小
def randChar(self):
basic='23456789abcdefghijklmnpqrstwxyzABCDEFGHIJKLMNPQRSTWXYZ'
return basic[random.randint(0,len(basic)-1)] #随机字符
def randBdColor(self):
return (random.randint(64,255),random.randint(64,255),random.randint(64,255)) #背景
def randTextColor(self):
return (random.randint(32, 127), random.randint(32, 127), random.randint(32, 127)) #随机颜色
def proPicture(self):
new_image=Image.new(self.mode,self.size,self.color) #创建新图像有三个默认参数:尺寸,颜色,模式
drawObject=ImageDraw.Draw(new_image) #创建一个可以对image操作的对象
line_num = random.randint(4,6) # 干扰线条数
for i in range(line_num):
#size=(240,60)
begin = (random.randint(0, self.size[0]), random.randint(0, self.size[1]))
end = (random.randint(0, self.size[0]), random.randint(0, self.size[1]))
drawObject.line([begin, end], self.randTextColor())
for x in range(240):
for y in range(60):
tmp = random.randint(0,50)
if tmp>30: #调整干扰点数量
drawObject.point((x,y),self.randBdColor())
randchar=''
for i in range(5):
rand=self.randChar()
randchar+=rand
drawObject.text([50*i+10,10],rand,self.randTextColor(),font=self.font) #写入字符
new_image = new_image.filter(ImageFilter.SHARPEN) # 滤镜
return new_image,randchar
@app.route('/<filename>')
def get_file(filename):
return send_from_directory(os.getcwd(),filename)
@app.route('/')
def index():
test=picture()
image,code=test.proPicture()
image.save('new.jpg')
url="http://127.0.0.1:5000/new.jpg"
return '<img src='+url+' /><br/>'+"图中的code为:"+code
#这里有缓存,需要CTRL+F5才会有效果
if __name__=="__main__":
app.run()
Кроме того, некоторые предшественники будут добавлять искаженные изображения, чтобы увеличить сложность различения.
# 图形扭曲参数
params = [1 - float(random.randint(1, 2)) / 100,
0,
0,
0,
1 - float(random.randint(1, 10)) / 100,
float(random.randint(1, 2)) / 500,
0.001,
float(random.randint(1, 2)) / 500
]
img = img.transform(size, Image.PERSPECTIVE, params) # 创建扭曲
здесьесть статьяОн представлен подробно:
Перспективно трансформирует текущее изображение, создавая новое изображение заданных размеров. Переменные данные представляют собой 8-кортеж (a,b,c,d,e,f,g,h), содержащий коэффициенты перспективного преобразования. Для каждого пикселя в выходном изображении новое значение получается из (ax + by + c)/(gx + hy + 1), (d x + ey + f)/(gx + hy + 1 в позиции входного изображения ) пикселей, используйте ближайший пиксель для приближения
Исходное определение этого включает аффинное преобразование, которое включает некоторые математические вычисления. Видя, что я немного запутался, я не стал добавлять это в свой код, поэтому сначала оставил дыру.
В этом месте многие веб-сайты теперь будут использовать другой способ ответа на вопросы. Я лично считаю, что это должен быть тот же метод, просто измените случайную строку на вопрос и измените метод проверки на ответ. Однако может быть удобнее хранить вопросы и ответы в базе данных здесь.
SMS-подтверждение
Иногда мне интересно, родился ли я слишком поздно. . . . . Если вы хотите что-то написать, вы можете найти хороший пост блога, следующим образом:Flask разрабатывает серию restful api (5) - SMS-код подтвержденияздесьоблачная связьЭто документ разработки платформы, используемой в этой статье, но платформа может быть выбрана свободно, и результаты будут такими же. Здесь я упрощу код предшественников, извлеку ключевой код об обработке кода проверки, использую Redis, я также воспользовался возможностью изучить волну, она действительно проста в использовании.
import redis
import random
phonenumber=188888888
#这里可以利用正则过滤一下电话号码,比如:
#/^(13[0-9]|14[5-9]|15[0-9]|16[6]|17[0-8]|18[0-9]|19[8-9])\d{8}$/
conn=redis.StrictRedis(host='127.0.0.1',port=6379)
def producCode():
verifyCode=str(random.randint(100000,999999))
pipe=conn.pipeline() #添加管道,可以一次连接执行多次命令
pipe.set("phone%s"%phonenumber,verifyCode)
pipe.expire("phone%s"%phonenumber,60) #设置过期时间一分钟
pipe.execute()
def checkCode():
pipe=conn.pipeline() #添加管道,可以一次连接执行多次命令
pipe.set('postNum%s'%phonenumber,'0')
validate_number = request.get_json().get('validate_number')
pipe.incr('postNum%s'%phonenumber) #记录提交次数防止爆破
if conn.get('postNum%s'%phonenumber)>3:
pass
...
if validate_number != validate_number_in_redis:
return jsonify({'code': 0, 'message': '验证没有通过'})
pipe.set('is_validate:%s' % phone_number, '1') #通过验证码设置value为1
pipe.expire('is_validate:%s' % phone_number, 120)
pipe.execute()
return jsonify({'code': 1, 'message': '验证通过'})
def postMessage():
result=conn.get("phone%s"%phonenumber)
#此时如果通过验证码,result为1,否则为0
...
#剩下的其他操作
Здесь упоминается, что утечка интерфейса приводит к взрыву проверочного кода, и я также добавил некоторые коды. Кроме того, некоторые функциональные модули также подвержены лазейкам, например, при изменении данных проверочный код должен совпадать не только с телефоном. Также проверьте согласованность имени пользователя, в противном случае, если пользователь просто передаст проверочный код, пользователь изменит его на свой номер, а проверочный код и номер мобильного телефона пройдут проверку. (Похоже, что большинство людей не совершают этой ошибки)
И ваш код напрямую передает имя пользователя для модификации, что может привести к сбросу пароля любым пользователем. или ваш код напрямую изменяет телефон как индекс
Справочная статья:аутентификация по собачьей книге
Разная подушка для обработки изображений
Некоторые основные понятия PIL
Изучение модулей Python PIL ImageDraw и ImageFont
Введение в модуль ImageFilter библиотеки обработки изображений Python PIL