From 7ca348a98ff012c53c7ad698398d9a6736d5384e Mon Sep 17 00:00:00 2001 From: wanglei <34475144@qq.com> Date: Mon, 24 Nov 2025 19:03:17 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9oauth=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E7=BB=93=E6=9E=9C=E5=86=85=E5=AE=B9=E5=B9=B6?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=BF=94=E5=9B=9E=E8=B7=B3=E8=BD=AC=E7=8A=B6?= =?UTF-8?q?=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/service/oauth/oauth.lua | 27 +++-- src/test/test.lua | 202 ++++++++++++++++++++++++++++++---- src/util/status.lua | 1 + src/validator/oauth/oauth.lua | 3 +- 4 files changed, 195 insertions(+), 38 deletions(-) diff --git a/src/service/oauth/oauth.lua b/src/service/oauth/oauth.lua index bb6b19b..7e9f614 100644 --- a/src/service/oauth/oauth.lua +++ b/src/service/oauth/oauth.lua @@ -113,25 +113,27 @@ local function authorizatePassword(args) local userid = res[1].id local client_id = args.client_id local client_secret = args.client_secret + local redirect_uri = args.redirect_uri code, res = oauthDao.getApplicationByUserid(userid, client_id, client_secret) if code ~= 0 or res == nil then resp:response(status.DATA_NONE_FOUNT) return end - local redirect_uri = res[1].redirect_uri + local uri_callback = res[1].redirect_uri -- 4.生成授权码(随机字符串,确保唯一性)(用户ID、客户端ID、scope、生成时间) - local auth_code, err = authcode.create(userid, client_id, redirect_uri) + local auth_code, err = authcode.create(userid, client_id, uri_callback) if not auth_code then ngx.log(ngx.ERR, "生成授权码失败: ", err) ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) end -- 5.存储用户信息,证明用户已经登陆 - client.create(userid, client_id, redirect_uri) + client.create(userid, client_id, uri_callback) -- 6.返回结果 local rest = {} rest.redirect_uri = redirect_uri rest.code = auth_code - resp:response(status.SUCCESS, rest) + resp:response(status.MOVED_TEMPORARILY, rest) + --resp:response(status.MOVED_TEMPORARILY, rest) end -- 通过code形式进行认证 @@ -150,14 +152,14 @@ local function authorizateCode(args) ngx.exit(ngx.HTTP_BAD_REQUEST) end -- 3.验证redirect_url地址的正确性 - local request_uri = code_data.redirect_uri - print("token request_uri:", request_uri) - if request_uri ~= args.redirect_uri then - print("token redirect_url:", request_uri, args.redirect_uri) - local login_url = "/login?redirect=" .. ngx.escape_uri(request_uri) - resp:response(status.PARAM_IS_INVALID, login_url) - return - end + local redirect_uri = code_data.redirect_uri + --print("token request_uri:", request_uri) + --if request_uri ~= args.redirect_uri then + -- print("token redirect_url:", request_uri, args.redirect_uri) + -- local login_url = "/login?redirect=" .. ngx.escape_uri(request_uri) + -- resp:response(status.PARAM_IS_INVALID, login_url) + -- return + --end -- 4.生成密钥对 --local pub_key, priv_key, err = rsa.generate_rsa_keys(2048) --if err then @@ -193,6 +195,7 @@ local function authorizateCode(args) return end -- 7.返回结果 + ret.redirect_uri = redirect_uri resp:response(status.SUCCESS, ret) end diff --git a/src/test/test.lua b/src/test/test.lua index 14eac2c..0d1c7de 100644 --- a/src/test/test.lua +++ b/src/test/test.lua @@ -36,17 +36,6 @@ if not ok then ngx.say("加载失败"..gd) return end - -function enabled(res, desc) - local str = " " .. desc .. " " - str = str .. string.rep(".", 37 - string.len(str)) - if res then - ngx.say(str .. " Enabled") - else - ngx.say(str .. " Disabled") - end -end - ngx.say("Lua-GD version: " .. gd.VERSION) ngx.say("Lua-GD features:") @@ -86,6 +75,7 @@ local uuid = require("util.uuid") local uid = uuid.generateUuid() ngx.say("uuid:"..uid) +--[[ local genpic = require("util.generatechaptcha") local filename, fp = genpic.getChaptcha() --redis中添加picgid为key,string为value的记录 @@ -96,6 +86,7 @@ ngx.header.content_type = "text/plain" ngx.header.picgid = filename --页面返回pic ngx.say(fp) +--]] --nginx退出 --ngx.exit(200) --do return end @@ -123,6 +114,11 @@ local digest = require "resty.openssl.digest" local pkey = require "resty.openssl.pkey" local str = require "resty.string" +local x509 = require "resty.openssl.x509" +local x509_name = require "resty.openssl.x509.name" +local x509_extension = require "resty.openssl.x509.extension" +local altname = require "resty.openssl.x509.altname" + --获取共享字段中的键值 local key = "11-code" local shared_dict = ngx.shared.codeDict @@ -142,6 +138,7 @@ ngx.say("code:"..code) ngx.say("-----") +--[[ -- 正确的schema定义 local schema = { type = "object", @@ -173,16 +170,13 @@ local schemaToken = { } -- 原始JSON字符串 ---local jsonStr = [[ ---{ --- "username": "admin", --- "password": "123456", --- "captcha": "", --- "checkKey": "" ---} ---]] +local jsonStr ={ + "username": "admin", + "password": "123456", + "captcha": "", + "checkKey": "" +} ---[[ ngx.req.read_body() --获取请求数据 local jsonStr = ngx.req.get_body_data() @@ -220,6 +214,7 @@ end do return end --]] +--[[ -- 生成RSA密钥对 local function generate_rsa_keys(length) local key, err = pkey.new({ @@ -370,11 +365,9 @@ end -- 执行示例 example() +--]] ---do --- return ---end - +--[[ -- 公钥加密(用于生成测试数据) local function rsa_encrypt(pub_key, plaintext) -- @@ -548,6 +541,167 @@ if not decoded then end ngx.say("JWT is valid: ", cjson.encode(decoded)) +--]] + + +-- 1. 生成 RSA 私钥(2048 位,可改为 4096 提升安全性) +local priv_key, err = pkey.new({ + type = "RSA", -- 密钥类型:RSA/ECC + bits = 2048, -- 密钥长度 + -- 可选:ECC 密钥配置(替换 RSA 时使用) + -- type = "EC", + -- curve = "prime256v1", -- P-256 曲线 +}) +if not priv_key then + error("生成私钥失败: " .. err) +end + +-- 2. 构建证书 DN(Distinguished Name)- 证书主体信息 +local dn, err = x509_name.new() +if not dn then + error("构建 DN 失败: " .. err) +end +-- 添加 DN 字段(按实际需求修改) +--local ok, err = dn:add_entry("C", "CN") -- 国家(2 字母代码) +--if not ok then error(err) end +--ok, err = dn:add_entry("ST", "Beijing") -- 省份 +--if not ok then error(err) end +--ok, err = dn:add_entry("L", "Beijing") -- 城市 +--if not ok then error(err) end +--ok, err = dn:add_entry("O", "MyCompany") -- 组织 +--if not ok then error(err) end +--ok, err = dn:add_entry("OU", "TechDept") -- 部门 +--if not ok then error(err) end +--ok, err = dn:add_entry("CN", "example.com") -- 通用名(证书绑定的域名) +--if not ok then error(err) end + +local ok, err = dn:add("C", "CN") -- 国家(2 字母代码) +if not ok then error(err) end +ok, err = dn:add("ST", "Beijing") -- 省份 +if not ok then error(err) end +ok, err = dn:add("L", "Beijing") -- 城市 +if not ok then error(err) end +ok, err = dn:add("O", "MyCompany") -- 组织 +if not ok then error(err) end +ok, err = dn:add("OU", "TechDept") -- 部门 +if not ok then error(err) end +ok, err = dn:add("CN", "example.com") -- 通用名(证书绑定的域名) +if not ok then error(err) end + +-- 3. 创建 X.509 证书对象并配置基础信息 +local cert, err = x509.new() +if not cert then + error("创建证书对象失败: " .. err) +end + +-- 设置版本(X509v3) +ok, err = cert:set_version(3) -- 版本号从 0 开始,3 对应 X509v3 +if not ok then error(err) end + +-- 设置序列号(唯一标识,建议用随机数避免冲突) +math.randomseed(os.time()) +local serial = math.random(1000000000, 9999999999) +print("serial value:", serial) +ok, err = cert:set_serial_number(serial) +if not ok then error(err) end + +-- 设置有效期(起始时间:当前时间,结束时间:365 天后) +local not_before = os.date("*t") +local not_after = os.date("*t") +not_after.year = not_after.year + 1 -- 有效期 1 年 +ok, err = cert:set_not_before(not_before) +if not ok then error(err) end +ok, err = cert:set_not_after(not_after) +if not ok then error(err) end + +-- 设置证书主体和颁发者(自签名:主体 = 颁发者) +ok, err = cert:set_subject_name(dn) +if not ok then error(err) end +ok, err = cert:set_issuer_name(dn) +if not ok then error(err) end + +-- 绑定公钥(从私钥中提取) +local pub_key, err = priv_key:get_public_key() +if not pub_key then error("提取公钥失败: " .. err) end +ok, err = cert:set_pubkey(pub_key) +if not ok then error(err) end + +-- 4. 配置证书扩展属性(关键!否则证书可能无法被浏览器/客户端信任) +-- 4.1 基本约束(自签名证书设为 CA:FALSE) +local ext, err = x509_extension.new( + "basicConstraints", "CA:FALSE", false -- 第三个参数:critical(是否强制) +) +if not ext then error(err) end +ok, err = cert:add_extension(ext) +if not ok then error(err) end + +-- 4.2 密钥用途(数字签名、服务器认证等) +ext, err = x509_extension.new( + "keyUsage", "digitalSignature, keyEncipherment", false +) +if not ext then error(err) end +ok, err = cert:add_extension(ext) +if not ok then error(err) end + +-- 4.3 扩展密钥用途(服务器/客户端认证) +ext, err = x509_extension.new( + "extendedKeyUsage", "serverAuth, clientAuth", false +) +if not ext then error(err) end +ok, err = cert:add_extension(ext) +if not ok then error(err) end + +-- 4.4 主题备用名称(SAN,支持多域名/IP,浏览器优先使用) +local san = altname.new() +ok, err = san:add("DNS", "example.com") -- 主域名 +ok, err = san:add("DNS", "www.example.com") -- 子域名 +ok, err = san:add("IP", "192.168.1.100") -- 绑定 IP(可选) +if not san then error(err) end +ext, err = x509_extension.new( + "subjectAltName", san:tostring(), false +) +if not ext then error(err) end +ok, err = cert:add_extension(ext) +if not ok then error(err) end + +-- 4.5 主题密钥标识(可选,增强安全性) +ext, err = x509_extension.new( + "subjectKeyIdentifier", "hash", false +) +if not ext then error(err) end +ok, err = cert:add_extension(ext) +if not ok then error(err) end + +-- 5. 用私钥自签名证书(签名算法:SHA256withRSA) +ok, err = cert:sign(priv_key, "SHA256") -- 算法支持:SHA1/SHA256/SHA512(推荐 SHA256+) +if not ok then + error("签名证书失败: " .. err) +end + +-- 6. 导出私钥和证书为 PEM 格式(保存到文件或返回给调用者) +local priv_key_pem, err = priv_key:to_pem("private") -- 私钥 PEM +local public_key_pem, err = pub_key:to_pem("public") -- 公钥 PEM +local cert_pem, err = cert:to_pem() -- 证书 PEM + +-- 保存到文件(示例) +--local priv_file = io.open("/path/to/example.key", "w") +--priv_file:write(priv_key_pem) +--priv_file:close() +-- +--local cert_file = io.open("/path/to/example.crt", "w") +--cert_file:write(cert_pem) +--cert_file:close() + +ngx.say("公钥文件:-----") +ngx.say(pub_key) +ngx.say("私钥文件:-----") +ngx.say(priv_key_pem) +ngx.say("证书文件:-----") +ngx.say(cert_pem) + +ngx.say("自签名证书生成成功!") +--print("私钥文件: /path/to/example.key") +--print("证书文件: /path/to/example.crt") --local original_text = "这是一段需要加密的敏感数据:123456" --local key = x509.PKey() diff --git a/src/util/status.lua b/src/util/status.lua index 0d3b6e3..d3cc2fc 100644 --- a/src/util/status.lua +++ b/src/util/status.lua @@ -22,6 +22,7 @@ local _M = { -- 成功状态码 SUCCESS = { code = 200, message = "操作成功" }, + MOVED_TEMPORARILY = { code = 304, message = "跳转URI" }, --[[ HTTP_SPECIAL_RESPONSE(300, "操作成功"), HTTP_MOVED_PERMANENTLY(301, "操作成功"), diff --git a/src/validator/oauth/oauth.lua b/src/validator/oauth/oauth.lua index d2e0b93..1390d7c 100644 --- a/src/validator/oauth/oauth.lua +++ b/src/validator/oauth/oauth.lua @@ -72,9 +72,8 @@ local schemaToken = { properties = { grant_type = { type = "string" }, code = { type = "string" }, - redirect_uri = { type = "string" }, }, - required = { "grant_type", "code", "redirect_uri" } + required = { "grant_type", "code" } } --根据授权码获取Access-Token