修改oauth中authorize和token函数业务逻辑,并增加生成code和code认证相关函数文件
This commit is contained in:
parent
2cbc0e3d3f
commit
03658c9004
|
|
@ -7,9 +7,9 @@ local resp = require("util.response")
|
||||||
local oauthDao = require("dao.oauth.oauth")
|
local oauthDao = require("dao.oauth.oauth")
|
||||||
local validator = require("validator.oauth.oauth")
|
local validator = require("validator.oauth.oauth")
|
||||||
local cjson = require("cjson.safe")
|
local cjson = require("cjson.safe")
|
||||||
local token = require("util.uuid")
|
|
||||||
local jwt = require "resty.jwt"
|
local jwt = require "resty.jwt"
|
||||||
local rsa = require("util.rsa")
|
local rsa = require("util.rsa")
|
||||||
|
local authcode = require("util.authcode")
|
||||||
|
|
||||||
local _M = {}
|
local _M = {}
|
||||||
|
|
||||||
|
|
@ -61,29 +61,14 @@ function _M:authorize()
|
||||||
resp:send(result)
|
resp:send(result)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
-- 4. 生成授权码(随机字符串,确保唯一性)
|
-- 4. 生成授权码(随机字符串,确保唯一性)(用户ID、客户端ID、scope、生成时间)
|
||||||
local function generate_code()
|
local auth_code, err = authcode.create("123456", args.client_id, ngx.var.request_uri, args.scope)
|
||||||
local str = require "resty.string"
|
if not auth_code then
|
||||||
local random = require "resty.random"
|
ngx.log(ngx.ERR, "生成授权码失败: ", err)
|
||||||
local bytes = random.bytes(16)
|
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
|
||||||
return str.to_hex(bytes)
|
|
||||||
end
|
end
|
||||||
local code = generate_code()
|
|
||||||
--print("authorize generate_code:", code)
|
|
||||||
-- 5、存储授权码信息(用户ID、客户端ID、scope、生成时间)
|
|
||||||
local code_key = "auth_code-"..code
|
|
||||||
local code_data = cjson.encode({
|
|
||||||
user_id = "123456",
|
|
||||||
client_id = args.client_id,
|
|
||||||
request_uri = ngx.var.request_uri,
|
|
||||||
scope = args.scope or "",
|
|
||||||
created_at = ngx.time()
|
|
||||||
})
|
|
||||||
local shared_dict = ngx.shared.codeDict
|
|
||||||
shared_dict:set(code_key, code_data)
|
|
||||||
shared_dict:expire(code_key, 300) --时效性为5分钟
|
|
||||||
--print("token set shared dict key:",code_key)
|
--print("token set shared dict key:",code_key)
|
||||||
-- 6. 重定向到客户端回调地址,携带授权码和原始 state(防 CSRF)
|
-- 5. 重定向到客户端回调地址,携带授权码和原始 state(防 CSRF)
|
||||||
local redirect_url = args.redirect_uri .. "?code=" .. code .. "&state=" .. args.state
|
local redirect_url = args.redirect_uri .. "?code=" .. code .. "&state=" .. args.state
|
||||||
local rest = {}
|
local rest = {}
|
||||||
rest.redirect_uri = args.redirect_uri
|
rest.redirect_uri = args.redirect_uri
|
||||||
|
|
@ -121,31 +106,19 @@ function _M:token()
|
||||||
|
|
||||||
-- 2. 校验必填参数验证数据是否符合json
|
-- 2. 校验必填参数验证数据是否符合json
|
||||||
local ok = validator.validateToken(args)
|
local ok = validator.validateToken(args)
|
||||||
--验证失败则返回
|
|
||||||
if not ok then
|
if not ok then
|
||||||
local result = resp:json(0x000001)
|
local result = resp:json(0x000001)
|
||||||
resp:send(result)
|
resp:send(result)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
-- 3. 校验 code 有效性
|
||||||
-- 4. 校验 code 有效性
|
local code_data, err = authcode.consume(args.code, args.client_id)
|
||||||
local code = args.code
|
if not code_data then
|
||||||
local code_key = "auth_code-"..code
|
ngx.log(ngx.ERR, "授权码验证失败: ", err)
|
||||||
local shared_dict = ngx.shared.codeDict
|
ngx.exit(ngx.HTTP_BAD_REQUEST)
|
||||||
local code_data = shared_dict:get(code_key)
|
|
||||||
if code_data == nil then
|
|
||||||
-- code 超出时效,需要重新获取code
|
|
||||||
--local result = resp:json(0x000001)
|
|
||||||
--resp:send(result)
|
|
||||||
local login_url = "/login?redirect=" .. ngx.escape_uri(ngx.var.request_uri)
|
|
||||||
local result = resp:json(ngx.HTTP_MOVED_TEMPORARILY, login_url)
|
|
||||||
resp:send(result)
|
|
||||||
return
|
|
||||||
end
|
end
|
||||||
--print("token code_data:", code_data)
|
-- 4、验证redirect_url地址的正确性
|
||||||
local jsonData = cjson.decode(code_data)
|
local request_uri = code_data.redirect_uri
|
||||||
-- 5、验证redirect_url地址的正确性
|
|
||||||
local request_uri = jsonData.redirect_uri
|
|
||||||
print("token request_uri:", request_uri)
|
print("token request_uri:", request_uri)
|
||||||
if request_uri ~= args.redirect_url then
|
if request_uri ~= args.redirect_url then
|
||||||
--print("token redirect_url:", request_uri, args.redirect_url)
|
--print("token redirect_url:", request_uri, args.redirect_url)
|
||||||
|
|
@ -154,9 +127,6 @@ function _M:token()
|
||||||
resp:send(result)
|
resp:send(result)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
-- 验证成功删除
|
|
||||||
shared_dict:delete(code_key)
|
|
||||||
|
|
||||||
-- 6. 生成密钥对
|
-- 6. 生成密钥对
|
||||||
local pub_key, priv_key, err = rsa.generate_rsa_keys(2048)
|
local pub_key, priv_key, err = rsa.generate_rsa_keys(2048)
|
||||||
if err then
|
if err then
|
||||||
|
|
@ -166,11 +136,11 @@ function _M:token()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
print("token pubkey:", pub_key)
|
print("token pubkey:", pub_key)
|
||||||
local user_id = jsonData.user_id
|
local user_id = code_data.user_id
|
||||||
--print("token user_id:", user_id)
|
--print("token user_id:", user_id)
|
||||||
local client_id = jsonData.client_id
|
local client_id = code_data.client_id
|
||||||
--print("token client_id:", client_id)
|
--print("token client_id:", client_id)
|
||||||
local scope = jsonData.scope
|
local scope = code_data.scope
|
||||||
--print("token scope:", scope)
|
--print("token scope:", scope)
|
||||||
local access_token_ttl = 10 * 60 --十分钟
|
local access_token_ttl = 10 * 60 --十分钟
|
||||||
local refresh_token_ttl = 7 * 24 * 3600 --7天
|
local refresh_token_ttl = 7 * 24 * 3600 --7天
|
||||||
|
|
@ -209,7 +179,6 @@ function _M:token()
|
||||||
iat = os.time(),
|
iat = os.time(),
|
||||||
exp = os.time() + 3600
|
exp = os.time() + 3600
|
||||||
}
|
}
|
||||||
|
|
||||||
-- 使用私钥生成JWT
|
-- 使用私钥生成JWT
|
||||||
local jwt_obj = jwt:sign(priv_key, {
|
local jwt_obj = jwt:sign(priv_key, {
|
||||||
header = {
|
header = {
|
||||||
|
|
@ -235,55 +204,6 @@ function _M:token()
|
||||||
resp:send(result)
|
resp:send(result)
|
||||||
end
|
end
|
||||||
|
|
||||||
--用户进行登陆然后验证返回code
|
|
||||||
function _M:login()
|
|
||||||
--获取远端客户端的IP地址
|
|
||||||
local client_ip = ngx.var.remote_addr
|
|
||||||
ngx.log(ngx.INFO, "client_ip:"..client_ip.." oauth login system")
|
|
||||||
--读取请求体的数据
|
|
||||||
ngx.req.read_body()
|
|
||||||
--获取请求数据
|
|
||||||
local body_data = ngx.req.get_body_data()
|
|
||||||
--验证json数据是否正确
|
|
||||||
local ok, data = pcall(cjson.decode, body_data)
|
|
||||||
if not ok then
|
|
||||||
local result = resp:json(0x000001)
|
|
||||||
resp:send(result)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
-- 验证数据是否符合json
|
|
||||||
local valid, errors = validator.validateLogin(data)
|
|
||||||
--验证失败则返回
|
|
||||||
if not valid then
|
|
||||||
local result = resp:json(0x000001)
|
|
||||||
resp:send(result)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local code, ret = oauthDao.login(data)
|
|
||||||
--读取数据错误
|
|
||||||
if code ~= 0 or table.getn(ret) < 0 then
|
|
||||||
local result = resp:json(0x000001)
|
|
||||||
resp:send(result)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 用户验证成功后,返回code值:用户id当前时间和随机数进行md5后生存一个code
|
|
||||||
local user_id = ret[1].id
|
|
||||||
local username = ret[1].username
|
|
||||||
local current_time = ngx.time()
|
|
||||||
local code = ngx.md5(user_id..current_time..math.random())
|
|
||||||
|
|
||||||
-- 将code放入到共享内存中
|
|
||||||
local key = code -- 作为键值
|
|
||||||
local shared_dict = ngx.shared.codeDict
|
|
||||||
shared_dict:set(key, user_id)
|
|
||||||
-- 数据时效性先设置5分钟
|
|
||||||
shared_dict:expire(key, 5 * 60)
|
|
||||||
--发送code到前端请求
|
|
||||||
local result = resp:json(0, code)
|
|
||||||
resp:send(result)
|
|
||||||
end
|
|
||||||
|
|
||||||
--根据Access-Token获取相应用户的账户信息
|
--根据Access-Token获取相应用户的账户信息
|
||||||
function _M:userinfo()
|
function _M:userinfo()
|
||||||
--获取用户认证数据信息
|
--获取用户认证数据信息
|
||||||
|
|
@ -295,7 +215,6 @@ function _M:userinfo()
|
||||||
ngx.status = ngx.HTTP_UNAUTHORIZED
|
ngx.status = ngx.HTTP_UNAUTHORIZED
|
||||||
ngx.exit(ngx.HTTP_UNAUTHORIZED)
|
ngx.exit(ngx.HTTP_UNAUTHORIZED)
|
||||||
end
|
end
|
||||||
|
|
||||||
--查找令牌中的Bearer前缀字符
|
--查找令牌中的Bearer前缀字符
|
||||||
local data = {}
|
local data = {}
|
||||||
data.Authorization = auth_header
|
data.Authorization = auth_header
|
||||||
|
|
@ -331,8 +250,6 @@ function _M:userinfo()
|
||||||
ngx.exit(ngx.HTTP_UNAUTHORIZED)
|
ngx.exit(ngx.HTTP_UNAUTHORIZED)
|
||||||
end
|
end
|
||||||
--获取token中的信息进行所需用户的信息返回
|
--获取token中的信息进行所需用户的信息返回
|
||||||
|
|
||||||
--
|
|
||||||
local ret = {}
|
local ret = {}
|
||||||
ret.sub = 248289761001
|
ret.sub = 248289761001
|
||||||
ret.name = "Jane Doe"
|
ret.name = "Jane Doe"
|
||||||
|
|
@ -344,43 +261,6 @@ function _M:userinfo()
|
||||||
resp:send(result)
|
resp:send(result)
|
||||||
end
|
end
|
||||||
|
|
||||||
--回收Access-Token
|
|
||||||
function _M:logout()
|
|
||||||
--读取请求体的数据
|
|
||||||
ngx.req.read_body()
|
|
||||||
--获取请求数据
|
|
||||||
local body_data = ngx.req.get_body_data()
|
|
||||||
--验证json数据是否正确
|
|
||||||
local ok, data = pcall(cjson.decode, body_data)
|
|
||||||
if not ok then
|
|
||||||
local result = resp:json(0x000001)
|
|
||||||
resp:send(result)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
-- 验证数据是否符合json
|
|
||||||
local ok = validator.validateLogout(data)
|
|
||||||
--验证失败则返回
|
|
||||||
if not ok then
|
|
||||||
local result = resp:json(0x000001)
|
|
||||||
resp:send(result)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
--用户验证成功后,返回code值:用户id当前时间和随机数进行md5后生存一个code
|
|
||||||
local user_id = "11"
|
|
||||||
local current_time = ngx.time()
|
|
||||||
local code = ngx.md5(user_id..current_time..math.random())
|
|
||||||
|
|
||||||
--将code放入到共享内存中
|
|
||||||
local key = user_id.."-code"
|
|
||||||
local shared_dict = ngx.shared.codeDict
|
|
||||||
shared_dict:set(key, code)
|
|
||||||
shared_dict:expire(key, 10)
|
|
||||||
--发送code到前端请求
|
|
||||||
local result = resp:json(0, code)
|
|
||||||
resp:send(result)
|
|
||||||
end
|
|
||||||
|
|
||||||
--根据Refresh-Token刷新Access-Token
|
--根据Refresh-Token刷新Access-Token
|
||||||
function _M:refresh()
|
function _M:refresh()
|
||||||
--读取请求体的数据
|
--读取请求体的数据
|
||||||
|
|
@ -404,27 +284,4 @@ function _M:refresh()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--验证token是否有效
|
|
||||||
function _M:checklogin()
|
|
||||||
--读取请求体的数据
|
|
||||||
ngx.req.read_body()
|
|
||||||
--获取请求数据
|
|
||||||
local body_data = ngx.req.get_body_data()
|
|
||||||
--验证json数据是否正确
|
|
||||||
local ok, data = pcall(cjson.decode, body_data)
|
|
||||||
if not ok then
|
|
||||||
local result = resp:json(0x000001)
|
|
||||||
resp:send(result)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
-- 验证数据是否符合json
|
|
||||||
local ok = validator.validateChecklogin(data)
|
|
||||||
--验证失败则返回
|
|
||||||
if not ok then
|
|
||||||
local result = resp:json(0x000001)
|
|
||||||
resp:send(result)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return _M
|
return _M
|
||||||
57
src/util/authcode.lua
Normal file
57
src/util/authcode.lua
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
---
|
||||||
|
--- Generated by EmmyLua(https://github.com/EmmyLua)
|
||||||
|
--- Created by admin.
|
||||||
|
--- DateTime: 2025/11/13 22:08
|
||||||
|
--- 授权码生成和认证
|
||||||
|
|
||||||
|
local str = require "resty.string"
|
||||||
|
local random = require "resty.random"
|
||||||
|
|
||||||
|
local _M = {}
|
||||||
|
|
||||||
|
-- 生成随机授权码(20字节)
|
||||||
|
local function generate_code()
|
||||||
|
local random_bytes = random.bytes(20, true)
|
||||||
|
return str.to_hex(random_bytes)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 存储授权码(有效期5分钟)
|
||||||
|
function _M.create(user_id, client_id, redirect_uri, scope)
|
||||||
|
local code = generate_code()
|
||||||
|
local code_key = "auth_code-"..code
|
||||||
|
local code_data = cjson.encode({
|
||||||
|
user_id = user_id,
|
||||||
|
client_id = client_id,
|
||||||
|
redirect_uri = redirect_uri,
|
||||||
|
scope = scope,
|
||||||
|
expires_at = ngx.time() + 300 -- 5分钟过期
|
||||||
|
})
|
||||||
|
local shared_dict = ngx.shared.codeDict
|
||||||
|
shared_dict:set(code_key, code_data)
|
||||||
|
shared_dict:expire(code_key, 300) --时效性为5分钟
|
||||||
|
return code
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 验证并消费授权码(一次性有效)
|
||||||
|
function _M.consume(code, client_id)
|
||||||
|
local code_key = "auth_code-"..code
|
||||||
|
local shared_dict = ngx.shared.codeDict
|
||||||
|
local data = shared_dict:get(code_key)
|
||||||
|
if data == nil then
|
||||||
|
return nil, "无效的授权码"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 消费后立即删除(一次性)
|
||||||
|
shared_dict:delete(code_key)
|
||||||
|
|
||||||
|
local code_data = cjson.decode(data)
|
||||||
|
if code_data.client_id ~= client_id then
|
||||||
|
return nil, "客户端不匹配"
|
||||||
|
end
|
||||||
|
if code_data.expires_at < ngx.time() then
|
||||||
|
return nil, "授权码已过期"
|
||||||
|
end
|
||||||
|
return code_data
|
||||||
|
end
|
||||||
|
|
||||||
|
return _M
|
||||||
|
|
@ -46,25 +46,6 @@ function _M.validateToken(jsonData)
|
||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
local schemaLogin = {
|
|
||||||
type = "object",
|
|
||||||
properties = {
|
|
||||||
username = { type = "string" },
|
|
||||||
password = { type = "string" },
|
|
||||||
captcha = { type = "string" },
|
|
||||||
checkKey = { type = "string" },
|
|
||||||
},
|
|
||||||
required = { "username", "password" }
|
|
||||||
}
|
|
||||||
|
|
||||||
--回收Access-Token
|
|
||||||
function _M.validateLogin(jsonData)
|
|
||||||
-- 验证数据是否符合schema
|
|
||||||
local validator = jsonschema.generate_validator(schemaLogin)
|
|
||||||
local result = validator(jsonData)
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
|
|
||||||
local schemaUserInfo = {
|
local schemaUserInfo = {
|
||||||
type = 'object',
|
type = 'object',
|
||||||
properties = {
|
properties = {
|
||||||
|
|
@ -80,22 +61,6 @@ function _M.validateUserinfo(jsonData)
|
||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
local schemaLogout = {
|
|
||||||
type = "object",
|
|
||||||
properties = {
|
|
||||||
Authorization = { type = "string" },
|
|
||||||
},
|
|
||||||
required = { "Authorization" }
|
|
||||||
}
|
|
||||||
|
|
||||||
--回收Access-Token
|
|
||||||
function _M.validateLogout(jsonData)
|
|
||||||
-- 验证数据是否符合schema
|
|
||||||
local validator = jsonschema.generate_validator(schemaLogout)
|
|
||||||
local result = validator(jsonData)
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
|
|
||||||
local schemaRefresh = {
|
local schemaRefresh = {
|
||||||
type = "object",
|
type = "object",
|
||||||
properties = {
|
properties = {
|
||||||
|
|
@ -112,20 +77,4 @@ function _M.validateRefresh(jsonData)
|
||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
local schemaChecklogin = {
|
|
||||||
type = "object",
|
|
||||||
properties = {
|
|
||||||
Authorization = { type = "string" },
|
|
||||||
},
|
|
||||||
required = { "Authorization" }
|
|
||||||
}
|
|
||||||
|
|
||||||
--验证token是否有效
|
|
||||||
function _M.validateChecklogin(jsonData)
|
|
||||||
-- 验证数据是否符合schema
|
|
||||||
local validator = jsonschema.generate_validator(schemaChecklogin)
|
|
||||||
local result = validator(jsonData)
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
|
|
||||||
return _M
|
return _M
|
||||||
Loading…
Reference in New Issue
Block a user