diff --git a/.flaskenv b/.flaskenv index 721d9f0..66006b5 100644 --- a/.flaskenv +++ b/.flaskenv @@ -14,7 +14,7 @@ MYSQL_HOST=127.0.0.1 MYSQL_PORT=3306 MYSQL_DATABASE=PearAdminFlask MYSQL_USERNAME=root -MYSQL_PASSWORD=123456 +MYSQL_PASSWORD=root # Redis 配置 # REDIS_HOST=127.0.0.1 diff --git a/Dockerfile b/Dockerfile index d24249f..aa5eb41 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,7 +19,7 @@ COPY . /app WORKDIR /app RUN pip --no-cache-dir install -i ${PIPURL} --upgrade pip \ - && pip --no-cache-dir install -i ${PIPURL} -r requirement/requirement-dev.txt \ + && pip --no-cache-dir install -i ${PIPURL} -r requirement/dev.txt \ && pip --no-cache-dir install -i ${PIPURL} gunicorn \ && chmod +x start.sh CMD ./start.sh \ No newline at end of file diff --git a/README.md b/README.md index 1cf9625..60b2ba8 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ Pear Admin Flask git clone https://gitee.com/pear-admin/pear-admin-flask # 安 装 -pip install -r requirement\requirement-dev.txt +pip install -r requirement\dev.txt # 配 置 .env diff --git a/applications/common/admin.py b/applications/common/admin.py index 8bc0c67..0958316 100644 --- a/applications/common/admin.py +++ b/applications/common/admin.py @@ -4,7 +4,7 @@ from io import BytesIO from flask import session, make_response, current_app from flask_login import current_user -from applications.common.utils.gen_captcha import gen_captcha +from applications.common.utils.gen_captcha import vieCode from applications.schemas import PowerOutSchema @@ -36,7 +36,7 @@ def make_menu_tree(): if p.enable == 0: continue # 一二级菜单 - if int(p.type) in [0,1] and p not in powers: + if int(p.type) in [0, 1] and p not in powers: powers.append(p) power_schema = PowerOutSchema(many=True) # 用已继承 ma.ModelSchema 类的自定制类生成序列化类 @@ -61,7 +61,8 @@ def make_menu_tree(): # 生成验证码 def get_captcha(): - code, image = gen_captcha() + image, code = vieCode().GetCodeImage() + code = ''.join(code).lower() out = BytesIO() session["code"] = code image.save(out, 'png') diff --git a/applications/common/script/initdb.py b/applications/common/script/initdb.py index 27358e3..51f5f57 100644 --- a/applications/common/script/initdb.py +++ b/applications/common/script/initdb.py @@ -55,6 +55,6 @@ def init_db(): return if init_database(): print('数据库%s创建成功' % str(DATABASE)) - execute_fromfile('test/pear.sql') + execute_fromfile('pear.sql') print('表创建成功') print('欢迎使用pear-admin-flask,请使用 flask run 命令启动程序') diff --git a/applications/common/utils/fonts/1.ttf b/applications/common/utils/fonts/1.ttf new file mode 100644 index 0000000..3a452b6 Binary files /dev/null and b/applications/common/utils/fonts/1.ttf differ diff --git a/applications/common/utils/gen_captcha.py b/applications/common/utils/gen_captcha.py index 068aa58..c72738c 100644 --- a/applications/common/utils/gen_captcha.py +++ b/applications/common/utils/gen_captcha.py @@ -1,14 +1,121 @@ -from captcha.image import ImageCaptcha - -from PIL import Image -from random import choices +import random, math +from PIL import Image, ImageDraw, ImageFont, ImageFilter -def gen_captcha(content='2345689abcdefghijklmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ'): - """ 生成验证码 """ - image = ImageCaptcha() - # 获取字符串 - captcha_text = "".join(choices(content, k=4)).lower() - # 生成图像 - captcha_image = Image.open(image.generate(captcha_text)) - return captcha_text, captcha_image +class vieCode: + __fontSize = 20 # 字体大小 + __width = 120 # 画布宽度 + __heigth = 45 # 画布高度 + __length = 4 # 验证码长度 + __draw = None # 画布 + __img = None # 图片资源 + __code = None # 验证码字符 + __str = None # 自定义验证码字符集 + __inCurve = True # 是否画干扰线 + __inNoise = True # 是否画干扰点 + __type = 2 # 验证码类型 1、纯字母 2、数字字母混合 + __fontPatn = 'applications/common/utils/fonts/1.ttf' # 字体 + + def GetCodeImage(self, size=80, length=4): + '''获取验证码图片 + @param int size 验证码大小 + @param int length 验证码长度 + ''' + # 准备基础数据 + self.__length = length + self.__fontSize = size + self.__width = self.__fontSize * self.__length + self.__heigth = int(self.__fontSize * 1.5) + + # 生成验证码图片 + self.__createCode() + self.__createImage() + self.__createNoise() + self.__printString() + self.__cerateFilter() + + return self.__img, self.__code + + def __cerateFilter(self): + '''模糊处理''' + self.__img = self.__img.filter(ImageFilter.BLUR) + filter = ImageFilter.ModeFilter(8) + self.__img = self.__img.filter(filter) + + def __createCode(self): + '''创建验证码字符''' + # 是否自定义字符集合 + if not self.__str: + # 源文本 + number = "3456789" + srcLetter = "qwertyuipasdfghjkzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM" + srcUpper = srcLetter.upper() + if self.__type == 1: + self.__str = number + else: + self.__str = srcLetter + srcUpper + number + + # 构造验证码 + self.__code = random.sample(self.__str, self.__length) + + def __createImage(self): + '''创建画布''' + bgColor = (random.randint(200, 255), random.randint(200, 255), random.randint(200, 255)) + self.__img = Image.new('RGB', (self.__width, self.__heigth), bgColor) + self.__draw = ImageDraw.Draw(self.__img) + + def __createNoise(self): + '''画干扰点''' + if not self.__inNoise: + return + font = ImageFont.truetype(self.__fontPatn, int(self.__fontSize / 1.5)) + for i in range(5): + # 杂点颜色 + noiseColor = (random.randint(150, 200), random.randint(150, 200), random.randint(150, 200)) + putStr = random.sample(self.__str, 2) + for j in range(2): + # 绘杂点 + size = (random.randint(-10, self.__width), random.randint(-10, self.__heigth)) + self.__draw.text(size, putStr[j], font=font, fill=noiseColor) + pass + + def __createCurve(self): + '''画干扰线''' + if not self.__inCurve: + return + x = y = 0 + + # 计算曲线系数 + a = random.uniform(1, self.__heigth / 2) + b = random.uniform(-self.__width / 4, self.__heigth / 4) + f = random.uniform(-self.__heigth / 4, self.__heigth / 4) + t = random.uniform(self.__heigth, self.__width * 2) + xend = random.randint(self.__width / 2, self.__width * 2) + w = (2 * math.pi) / t + + # 画曲线 + color = (random.randint(30, 150), random.randint(30, 150), random.randint(30, 150)) + for x in range(xend): + if w != 0: + for k in range(int(self.__heigth / 10)): + y = a * math.sin(w * x + f) + b + self.__heigth / 2 + i = int(self.__fontSize / 5) + while i > 0: + px = x + i + py = y + i + k + self.__draw.point((px, py), color) + i -= i + + def __printString(self): + '''打印验证码字符串''' + font = ImageFont.truetype(self.__fontPatn, self.__fontSize) + x = 0 + # 打印字符到画板 + for i in range(self.__length): + # 设置字体随机颜色 + color = (random.randint(30, 150), random.randint(30, 150), random.randint(30, 150)) + # 计算座标 + x = random.uniform(self.__fontSize * i * 0.95, self.__fontSize * i * 1.1) + y = self.__fontSize * random.uniform(0.3, 0.5) + # 打印字符 + self.__draw.text((x, y), self.__code[i], font=font, fill=color) diff --git a/applications/extensions/__init__.py b/applications/extensions/__init__.py index 2e7e108..14f9cc8 100644 --- a/applications/extensions/__init__.py +++ b/applications/extensions/__init__.py @@ -2,7 +2,6 @@ from flask import Flask from .init_sqlalchemy import db, ma, init_databases from .init_login import init_login_manager -from .init_debug_tool import init_debug_tool from .init_template_directives import init_template_directives from .init_error_views import init_error_views from .init_mail import init_mail @@ -12,7 +11,6 @@ from .init_dotenv import init_dotenv def init_plugs(app: Flask) -> None: - # init_debug_tool(app) init_login_manager(app) init_databases(app) init_template_directives(app) diff --git a/applications/extensions/init_debug_tool.py b/applications/extensions/init_debug_tool.py deleted file mode 100644 index 8182457..0000000 --- a/applications/extensions/init_debug_tool.py +++ /dev/null @@ -1,7 +0,0 @@ -from flask import Flask -from flask_debugtoolbar import DebugToolbarExtension - - -def init_debug_tool(app: Flask): - toolbar = DebugToolbarExtension() - toolbar.init_app(app) diff --git a/test/pear.sql b/pear.sql similarity index 100% rename from test/pear.sql rename to pear.sql diff --git a/requirement/dev.txt b/requirement/dev.txt new file mode 100644 index 0000000..901ad35 --- /dev/null +++ b/requirement/dev.txt @@ -0,0 +1,15 @@ +Flask +Flask-APScheduler +Flask-Migrate +Flask-Login +Flask_Reuploaded +Flask-SQLAlchemy +flask-marshmallow +marshmallow-sqlalchemy +PyMySQL +psutil +Flask-Mail +sqlparse +Pillow +python-dotenv +webargs \ No newline at end of file diff --git a/requirement/requirement-dev.txt b/requirement/requirement-dev.txt deleted file mode 100644 index e039497..0000000 --- a/requirement/requirement-dev.txt +++ /dev/null @@ -1,17 +0,0 @@ -Flask==2.1.1 -Flask-APScheduler==1.12.2 -Flask-DebugToolbar==0.11.0 -Flask-Migrate==3.1.0 -Flask-Login==0.6.0 -Flask_Reuploaded==0.5.0 -Flask-SQLAlchemy==2.5.1 -flask-marshmallow==0.14.0 -marshmallow-sqlalchemy==0.26.1 -PyMySQL==1.0.2 -psutil==5.8.0 -Flask-Mail==0.9.1 -sqlparse==0.4.2 -captcha==0.3 -Pillow==8.2.0 -python-dotenv==0.19.1 -webargs==8.0.1 \ No newline at end of file