feat: verification
This commit is contained in:
@@ -73,3 +73,18 @@ def send_excel(file_handler, file_name, suffix='xlsx'):
|
|||||||
attachment_filename='{}.{}'.format(file_name, suffix),
|
attachment_filename='{}.{}'.format(file_name, suffix),
|
||||||
as_attachment=True
|
as_attachment=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def send_png(img_handler, name='image'):
|
||||||
|
"""
|
||||||
|
发送图片文件(可用于验证码)
|
||||||
|
:param img_handler:
|
||||||
|
:param name:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
return send_file(
|
||||||
|
img_handler,
|
||||||
|
mimetype='image/png',
|
||||||
|
attachment_filename='{}.png'.format(name),
|
||||||
|
as_attachment=True
|
||||||
|
)
|
||||||
|
3
nc_http/core/verification/__init__.py
Normal file
3
nc_http/core/verification/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
用户验证码相关
|
||||||
|
"""
|
38
nc_http/core/verification/image.py
Normal file
38
nc_http/core/verification/image.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import random
|
||||||
|
import string
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
from captcha.image import ImageCaptcha
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleImageCaptcha:
|
||||||
|
|
||||||
|
def __init__(self, width=150, height=50, captcha_length=4, characters=string.digits, *args, **kwargs):
|
||||||
|
self.__width = width
|
||||||
|
self.__height = height
|
||||||
|
self.__captcha_length = captcha_length
|
||||||
|
self.__characters = characters
|
||||||
|
|
||||||
|
self.__str = ''.join([random.choice(characters) for _ in range(captcha_length)])
|
||||||
|
|
||||||
|
generator = ImageCaptcha(width=self.__width, height=self.__height, *args, **kwargs)
|
||||||
|
self.__image = generator.create_captcha_image(
|
||||||
|
chars=self.__str,
|
||||||
|
color=(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)),
|
||||||
|
background=(255, 255, 255)
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def str(self):
|
||||||
|
return self.__str
|
||||||
|
|
||||||
|
@property
|
||||||
|
def image(self):
|
||||||
|
return self.__image
|
||||||
|
|
||||||
|
@property
|
||||||
|
def image_handler(self):
|
||||||
|
output = BytesIO()
|
||||||
|
self.__image.save(output, 'png')
|
||||||
|
output.seek(0)
|
||||||
|
return output
|
64
nc_http/core/verification/storage.py
Normal file
64
nc_http/core/verification/storage.py
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
from abc import abstractmethod, ABC
|
||||||
|
|
||||||
|
from nc_http.core.verification.image import SimpleImageCaptcha
|
||||||
|
|
||||||
|
|
||||||
|
class BaseCaptchaStorage(ABC):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create(cls, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
创建验证码
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
captcha = SimpleImageCaptcha(*args, **kwargs)
|
||||||
|
cls.storage(captcha.str)
|
||||||
|
return captcha
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@abstractmethod
|
||||||
|
def storage(captcha_code):
|
||||||
|
"""
|
||||||
|
记录生成的验证码字符
|
||||||
|
:param captcha_code:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@abstractmethod
|
||||||
|
def validate(captcha_code):
|
||||||
|
"""
|
||||||
|
确认验证码正确性
|
||||||
|
:param captcha_code:
|
||||||
|
:return: str
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class SampleCaptchaStorage(BaseCaptchaStorage):
|
||||||
|
"""
|
||||||
|
验证码池样例实现
|
||||||
|
|
||||||
|
* 仅作测试使用,勿用于生产环境
|
||||||
|
"""
|
||||||
|
storage_dict = {}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def storage(captcha_code):
|
||||||
|
SampleCaptchaStorage.storage_dict[captcha_code] = True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@abstractmethod
|
||||||
|
def validate(captcha_code):
|
||||||
|
valid = SampleCaptchaStorage.storage_dict.get(captcha_code)
|
||||||
|
if valid:
|
||||||
|
del SampleCaptchaStorage.storage_dict[captcha_code]
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
test_captcha = SampleCaptchaStorage.create()
|
||||||
|
is_valid = SampleCaptchaStorage.validate('test_code')
|
||||||
|
print(is_valid)
|
||||||
|
is_valid = SampleCaptchaStorage.validate(test_captcha.str)
|
||||||
|
print(is_valid)
|
17
nc_http/tests/verification.py
Normal file
17
nc_http/tests/verification.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import unittest
|
||||||
|
|
||||||
|
from nc_http.core.verification.storage import SampleCaptchaStorage
|
||||||
|
|
||||||
|
|
||||||
|
class VerificationTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_storage(self):
|
||||||
|
captcha = SampleCaptchaStorage.create()
|
||||||
|
is_valid = SampleCaptchaStorage.validate('test_code')
|
||||||
|
self.assertEqual(is_valid, False)
|
||||||
|
is_valid = SampleCaptchaStorage.validate(captcha.str)
|
||||||
|
self.assertEqual(is_valid, True)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
Reference in New Issue
Block a user