diff --git a/conf/system/system.conf b/conf/system/system.conf index 6b31c27..2200d08 100644 --- a/conf/system/system.conf +++ b/conf/system/system.conf @@ -48,6 +48,11 @@ location /yum/v1/system/users { content_by_lua_file '${APP_PATH}/src/api/system/user.lua'; } +#登陆时图片验证码相关 +location /yum/v1/system/captcha { + content_by_lua_file '${APP_PATH}/src/api/system/captcha.lua'; +} + ###################################################### ### oauth2.0 + openIDC 接口文件处理 ### ###################################################### diff --git a/src/api/system/captcha.lua b/src/api/system/captcha.lua new file mode 100644 index 0000000..41c4c6b --- /dev/null +++ b/src/api/system/captcha.lua @@ -0,0 +1,43 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by admin. +--- DateTime: 2025/11/21 11:50 +--- 验证码图片接口 + +--解析url路由过滤库 +local radix = require("resty.radixtree") +--数据表业务处理 +local systemCaptcha = require("service.system.captcha") + +--定义相关路由,前端接口url地址 +local routes = { + --验证码图片相关路由接口 + { + paths = { "/yum/v1/system/captcha" }, + methods = { "GET" }, + handler = systemCaptcha.getCaptcha, + }, +} + +-- 初始化路由 +local rx, err = radix.new(routes) +if not rx then + ngx.say("Not Found") + ngx.exit(ngx.HTTP_NOT_FOUND) +end + +--获取访问的uri地址 +local uri = ngx.var.uri +local opts = { + host = ngx.var.host, + method = ngx.var.request_method, + remote_addr = ngx.var.remote_addr, + matched = {} +} + +-- 进行路由匹配和相关函数调用 +local ok = rx:dispatch(uri, opts, opts.matched) +if not ok then + ngx.say("Not Found") + ngx.exit(ngx.HTTP_NOT_FOUND) +end diff --git a/src/service/system/captcha.lua b/src/service/system/captcha.lua new file mode 100644 index 0000000..63480c1 --- /dev/null +++ b/src/service/system/captcha.lua @@ -0,0 +1,44 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by admin. +--- DateTime: 2025/11/21 11:55 +--- 验证码相关函数 + +local _M = {} + +local status = require("util.status") +local resp = require("util.response") +local genpic = require("util.generatechaptcha") +local red = require("share.redis") + +--生成图片文件 +function _M.getCaptcha() + local filename, base64_data, captchaText = genpic.get_captcha_base64() + --将文件名存储到redis中 超时时间5分钟 + local key = "captcha-"..filename + red:set(key, captchaText) + red:expire(key, 5 * 60) + + -- 4.返回结果 + local ret = { + picgid = filename, + pic = base64_data + } + resp:response(status.SUCCESS, ret) +end + +--验证图片上的验证码 +function _M.checkCaptcha() + +end + +--验证码删除 +function _M.deleteCaptcha() + --获取请求中参数 + local args = ngx.req.get_uri_args() + --其中image为要删除的验证码图片的picgid。 + local picgid = args["picgid"] + red:del(picgid) +end + +return _M \ No newline at end of file diff --git a/src/util/generatechaptcha.lua b/src/util/generatechaptcha.lua index 4819734..4789024 100644 --- a/src/util/generatechaptcha.lua +++ b/src/util/generatechaptcha.lua @@ -12,54 +12,66 @@ local _M = {} --在32个备选字符中随机筛选4个作为captcha字符串 local dict = {'A','B','C','D','E','F','G','H','J','K','L','M','N','P','Q','R','S','T','U','V','W','X','Y','Z','2','3','4','5','6','7','8','9'} -function _M.getChaptcha() - local stringmark = "" - for i = 1, 4 do - stringmark = stringmark..dict[math.random(1,32)] - end - +-- 生成验证码图片 +local function generate_captcha() --图片基本info local uid = uuid.generateUuid() --picgid - local filename = "1"..uid..".png" + local filename = uid --图片78x26 - local xsize = 78 - local ysize = 26 - --字体大小 - local wsize = 17.5 - --干扰线(yes/no) - local line = "yes" + local width = 78 + local height = 26 + -- 创建画布 + local im = gd.createTrueColor(width, height) - --创建面板 - local im = gd.createTrueColor(xsize, ysize) - --定义颜色 + -- 设置背景色(白色) + local white = im:colorAllocate(255, 255, 255) + im:filledRectangle(0, 0, width, height, white) + + -- 设置文本颜色(黑色) local black = im:colorAllocate(0, 0, 0) - local grey = im:colorAllocate(202, 202, 202) - local color = {} - for c = 1, 100 do - color[c] = im:colorAllocate(math.random(100), math.random(100), math.random(100)) + + -- 生成随机验证码(4位数字字母) + math.randomseed(os.time()) + local captcha_text = "" + for i = 1, 4 do + captcha_text = captcha_text..dict[math.random(1,32)] end - --画背景 - x, y = im:sizeXY() - im:filledRectangle(0, 0, x, y, grey) - --画字符 + -- 在图片上绘制验证码文本 gd.useFontConfig(true) for i = 1, 4 do - k = (i - 1) * 16 + 3 - im:stringFT(color[math.random(100)], "Arial:bold", wsize, math.rad(math.random(-10,10)), k, 22, string.sub(stringmark, i, i)) + local char = string.sub(captcha_text, i, i) + local x = 10 + (i-1)*25 + math.random(-5,5) + local y = 10 + math.random(-5,5) + local angle = math.random(-20, 20) + im:stringFT(black, "Arial:bold", 18, angle, x, 30, char) end - --干扰线点 - if line == "yes" then - for j = 1, math.random(3) do - im:line(math.random(xsize), math.random(ysize), math.random(xsize), math.random(ysize), color[math.random(100)]) - end - for p = 1, 20 do - im:setPixel(math.random(xsize), math.random(ysize), color[math.random(100)]) - end + -- 添加干扰线 + for i = 1, 5 do + local line_color = im:colorAllocate(math.random(0,255), math.random(0,255), math.random(0,255)) + im:line(math.random(0, height), math.random(0, width), math.random(0,height), math.random(0, width), line_color) end - --流输出 - local fp = im:pngStr(75) - return filename, fp + -- 添加噪点 + for i = 1, 100 do + local dot_color = im:colorAllocate(math.random(0,255), math.random(0,255), math.random(0,255)) + im:setPixel(math.random(0, height), math.random(0, width), dot_color) + end + -- 将图片转换为PNG格式的二进制数据 + local png_data = im:pngStr(75) + return filename, captcha_text, png_data +end + +-- 生成验证码并返回Base64编码 +function _M.get_captcha_base64() + local filename, captcha_text, png_data = generate_captcha() + + if not png_data then + ngx.log(ngx.ERR, "Failed to generate captcha image") + return nil, nil, nil + end + -- 对图片数据进行Base64编码 + local base64_data = ngx.encode_base64(png_data) + return filename, base64_data, captcha_text end return _M \ No newline at end of file