Compare commits
No commits in common. "54cc8fbfbfb6cae5756b0dab8b6f2a26b722ce6b" and "03658c90042a5edae01cdceba0d8a17baa8be868" have entirely different histories.
54cc8fbfbf
...
03658c9004
|
|
@ -25,18 +25,36 @@ local routes = {
|
||||||
methods = { "GET", "POST" },
|
methods = { "GET", "POST" },
|
||||||
handler = oauthService.token,
|
handler = oauthService.token,
|
||||||
},
|
},
|
||||||
|
--通过用户名和密码进行验证
|
||||||
|
{
|
||||||
|
paths = { "/yum/v1/oauth/v2/login" },
|
||||||
|
methods = { "POST" },
|
||||||
|
handler = oauthService.login,
|
||||||
|
},
|
||||||
--根据Access-Token获取相应用户的账户信息
|
--根据Access-Token获取相应用户的账户信息
|
||||||
{
|
{
|
||||||
paths = { "/yum/v1/oauth/v2/userinfo" },
|
paths = { "/yum/v1/oauth/v2/userinfo" },
|
||||||
methods = { "POST" },
|
methods = { "POST" },
|
||||||
handler = oauthService.userinfo,
|
handler = oauthService.userinfo,
|
||||||
},
|
},
|
||||||
|
--回收Access-Token
|
||||||
|
{
|
||||||
|
paths = { "/yum/v1/oauth/v2/logout" },
|
||||||
|
methods = { "POST" },
|
||||||
|
handler = oauthService.logout,
|
||||||
|
},
|
||||||
--根据Refresh-Token刷新Access-Token
|
--根据Refresh-Token刷新Access-Token
|
||||||
{
|
{
|
||||||
paths = { "/yum/v1/oauth/v2/refresh" },
|
paths = { "/yum/v1/oauth/v2/refresh" },
|
||||||
methods = { "GET", "POST" },
|
methods = { "GET", "POST" },
|
||||||
handler = oauthService.refresh,
|
handler = oauthService.refresh,
|
||||||
},
|
},
|
||||||
|
--验证token是否有效
|
||||||
|
{
|
||||||
|
paths = { "/yum/v1/oauth/v2/checklogin" },
|
||||||
|
methods = { "POST" },
|
||||||
|
handler = oauthService.checklogin,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
-- 初始化路由
|
-- 初始化路由
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ local cjson = require("cjson.safe")
|
||||||
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 authcode = require("util.authcode")
|
||||||
local token = require("util.token")
|
|
||||||
|
|
||||||
local _M = {}
|
local _M = {}
|
||||||
|
|
||||||
|
|
@ -63,7 +62,7 @@ function _M:authorize()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
-- 4. 生成授权码(随机字符串,确保唯一性)(用户ID、客户端ID、scope、生成时间)
|
-- 4. 生成授权码(随机字符串,确保唯一性)(用户ID、客户端ID、scope、生成时间)
|
||||||
local auth_code, err = authcode.create("123456", args.client_id, args.redirect_uri, args.scope)
|
local auth_code, err = authcode.create("123456", args.client_id, ngx.var.request_uri, args.scope)
|
||||||
if not auth_code then
|
if not auth_code then
|
||||||
ngx.log(ngx.ERR, "生成授权码失败: ", err)
|
ngx.log(ngx.ERR, "生成授权码失败: ", err)
|
||||||
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
|
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
|
||||||
|
|
@ -73,7 +72,7 @@ function _M:authorize()
|
||||||
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
|
||||||
rest.code = auth_code
|
rest.code = code
|
||||||
rest.state = args.state
|
rest.state = args.state
|
||||||
local result = resp:json(ngx.HTTP_OK, rest)
|
local result = resp:json(ngx.HTTP_OK, rest)
|
||||||
resp:send(result)
|
resp:send(result)
|
||||||
|
|
@ -113,7 +112,7 @@ function _M:token()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
-- 3. 校验 code 有效性
|
-- 3. 校验 code 有效性
|
||||||
local code_data, err = authcode.consume(args.code)--, args.client_id)
|
local code_data, err = authcode.consume(args.code, args.client_id)
|
||||||
if not code_data then
|
if not code_data then
|
||||||
ngx.log(ngx.ERR, "授权码验证失败: ", err)
|
ngx.log(ngx.ERR, "授权码验证失败: ", err)
|
||||||
ngx.exit(ngx.HTTP_BAD_REQUEST)
|
ngx.exit(ngx.HTTP_BAD_REQUEST)
|
||||||
|
|
@ -121,39 +120,86 @@ function _M:token()
|
||||||
-- 4、验证redirect_url地址的正确性
|
-- 4、验证redirect_url地址的正确性
|
||||||
local request_uri = code_data.redirect_uri
|
local request_uri = code_data.redirect_uri
|
||||||
print("token request_uri:", request_uri)
|
print("token request_uri:", request_uri)
|
||||||
if request_uri ~= args.redirect_uri then
|
if request_uri ~= args.redirect_url then
|
||||||
print("token redirect_url:", request_uri, args.redirect_uri)
|
--print("token redirect_url:", request_uri, args.redirect_url)
|
||||||
local login_url = "/login?redirect=" .. ngx.escape_uri(request_uri)
|
local login_url = "/login?redirect=" .. ngx.escape_uri(request_uri)
|
||||||
local result = resp:json(ngx.HTTP_MOVED_TEMPORARILY, login_url)
|
local result = resp:json(ngx.HTTP_MOVED_TEMPORARILY, login_url)
|
||||||
resp:send(result)
|
resp:send(result)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
-- 5. 生成密钥对
|
-- 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
|
||||||
print("密钥生成失败: ", err)
|
--print("密钥生成失败: ", err)
|
||||||
local result = resp:json(0x00001)
|
local result = resp:json(0x00001)
|
||||||
resp:send(result)
|
resp:send(result)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
print("token pubkey:", pub_key)
|
print("token pubkey:", pub_key)
|
||||||
local user_id = code_data.user_id
|
local user_id = code_data.user_id
|
||||||
|
--print("token user_id:", user_id)
|
||||||
local client_id = code_data.client_id
|
local client_id = code_data.client_id
|
||||||
|
--print("token client_id:", client_id)
|
||||||
local scope = code_data.scope
|
local scope = code_data.scope
|
||||||
-- 6 生成新 Access Token
|
--print("token scope:", scope)
|
||||||
local new_access_token = token.generate_access_token(priv_key, user_id, client_id, scope)
|
local access_token_ttl = 10 * 60 --十分钟
|
||||||
-- 7 生成新 Refresh Token(滚动刷新)
|
local refresh_token_ttl = 7 * 24 * 3600 --7天
|
||||||
local new_refresh_token = token.generate_refresh_token(priv_key, user_id, client_id, scope)
|
-- 7 生成新 Access Token
|
||||||
-- 8、生存id_token
|
local access_payload = {
|
||||||
local new_id_token = token.generate_id_token(priv_key, user_id, client_id, scope)
|
sub = user_id, -- 用户ID
|
||||||
|
client_id = client_id,
|
||||||
|
scope = scope or "",
|
||||||
|
exp = ngx.time() + access_token_ttl,
|
||||||
|
jti = ngx.md5(ngx.time() .. math.random() .. client_id) -- 唯一标识
|
||||||
|
}
|
||||||
|
local new_access_token = jwt:sign(priv_key, {
|
||||||
|
header = { typ = "JWT", alg = "HS256" },
|
||||||
|
payload = access_payload
|
||||||
|
})
|
||||||
|
|
||||||
|
-- 8 生成新 Refresh Token(滚动刷新)
|
||||||
|
local refresh_payload = {
|
||||||
|
sub = user_id,
|
||||||
|
client_id = client_id,
|
||||||
|
scope = scope or "",
|
||||||
|
exp = ngx.time() + refresh_token_ttl,
|
||||||
|
jti = ngx.md5(ngx.time() .. math.random() * 1000 .. client_id)
|
||||||
|
}
|
||||||
|
local new_refresh_token = jwt:sign(priv_key, {
|
||||||
|
header = { typ = "JWT", alg = "HS256" },
|
||||||
|
payload = refresh_payload
|
||||||
|
})
|
||||||
|
|
||||||
|
-- 9、生存id_token
|
||||||
|
-- 创建JWT的payload
|
||||||
|
local payload = {
|
||||||
|
iss = request_uri,
|
||||||
|
sub = user_id,
|
||||||
|
name = user_id,
|
||||||
|
iat = os.time(),
|
||||||
|
exp = os.time() + 3600
|
||||||
|
}
|
||||||
|
-- 使用私钥生成JWT
|
||||||
|
local jwt_obj = jwt:sign(priv_key, {
|
||||||
|
header = {
|
||||||
|
type = "JWT",
|
||||||
|
alg = "RS256"
|
||||||
|
},
|
||||||
|
payload = payload
|
||||||
|
})
|
||||||
|
if not jwt_obj then
|
||||||
|
local result = resp:json(0x00001)
|
||||||
|
resp:send(result)
|
||||||
|
return
|
||||||
|
end
|
||||||
--ngx.say("Generated JWT: ", jwt_obj)
|
--ngx.say("Generated JWT: ", jwt_obj)
|
||||||
-- 9. 返回结果
|
-- 10. 返回结果
|
||||||
local ret = {}
|
local ret = {}
|
||||||
ret.access_token = new_access_token
|
ret.access_token = new_access_token
|
||||||
ret.token_type = "Bearer"
|
ret.token_type = "Bearer"
|
||||||
ret.expires_in = 10 * 60
|
ret.expires_in = access_token_ttl
|
||||||
ret.refresh_token = new_refresh_token
|
ret.refresh_token = new_refresh_token
|
||||||
ret.id_token = new_id_token
|
ret.id_token = jwt_obj
|
||||||
local result = resp:json(ngx.HTTP_OK, ret)
|
local result = resp:json(ngx.HTTP_OK, ret)
|
||||||
resp:send(result)
|
resp:send(result)
|
||||||
end
|
end
|
||||||
|
|
@ -163,13 +209,13 @@ function _M:userinfo()
|
||||||
--获取用户认证数据信息
|
--获取用户认证数据信息
|
||||||
local auth_header = ngx.var.http_Authorization
|
local auth_header = ngx.var.http_Authorization
|
||||||
|
|
||||||
-- 1.如果请求头中没有令牌,则直接返回401
|
--如果请求头中没有令牌,则直接返回401
|
||||||
if auth_header == nil or auth_header == "" then
|
if auth_header == nil or auth_header == "" then
|
||||||
ngx.log(ngx.WARN, "没有找到令牌数据")
|
ngx.log(ngx.WARN, "没有找到令牌数据")
|
||||||
ngx.status = ngx.HTTP_UNAUTHORIZED
|
ngx.status = ngx.HTTP_UNAUTHORIZED
|
||||||
ngx.exit(ngx.HTTP_UNAUTHORIZED)
|
ngx.exit(ngx.HTTP_UNAUTHORIZED)
|
||||||
end
|
end
|
||||||
-- 2.查找令牌中的Bearer前缀字符
|
--查找令牌中的Bearer前缀字符
|
||||||
local data = {}
|
local data = {}
|
||||||
data.Authorization = auth_header
|
data.Authorization = auth_header
|
||||||
local ok = validator.validateUserinfo(data)
|
local ok = validator.validateUserinfo(data)
|
||||||
|
|
@ -178,7 +224,7 @@ 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
|
||||||
-- 3.获取token的数据值
|
--获取token的数据值
|
||||||
local token = string.sub(auth_header,8)
|
local token = string.sub(auth_header,8)
|
||||||
--校验令牌
|
--校验令牌
|
||||||
local pub_key, priv_key, err = rsa.generate_rsa_keys(2048)
|
local pub_key, priv_key, err = rsa.generate_rsa_keys(2048)
|
||||||
|
|
@ -188,7 +234,6 @@ function _M:userinfo()
|
||||||
resp:send(result)
|
resp:send(result)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
-- 5.对token进行验证
|
|
||||||
print("userinfo pubkey:", pub_key)
|
print("userinfo pubkey:", pub_key)
|
||||||
local jwt_obj = jwt:verify(pub_key, token)
|
local jwt_obj = jwt:verify(pub_key, token)
|
||||||
--如果校验结果中的verified==false,则表示令牌无效
|
--如果校验结果中的verified==false,则表示令牌无效
|
||||||
|
|
@ -204,7 +249,7 @@ 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
|
||||||
-- 6.获取token中的信息进行所需用户的信息返回
|
--获取token中的信息进行所需用户的信息返回
|
||||||
local ret = {}
|
local ret = {}
|
||||||
ret.sub = 248289761001
|
ret.sub = 248289761001
|
||||||
ret.name = "Jane Doe"
|
ret.name = "Jane Doe"
|
||||||
|
|
|
||||||
|
|
@ -6,20 +6,18 @@
|
||||||
|
|
||||||
local str = require "resty.string"
|
local str = require "resty.string"
|
||||||
local random = require "resty.random"
|
local random = require "resty.random"
|
||||||
local cjson = require("cjson.safe")
|
|
||||||
|
|
||||||
local _M = {}
|
local _M = {}
|
||||||
|
|
||||||
-- 生成随机授权码(16字节)
|
-- 生成随机授权码(20字节)
|
||||||
local function generate_code()
|
local function generate_code()
|
||||||
local random_bytes = random.bytes(16)
|
local random_bytes = random.bytes(20, true)
|
||||||
return str.to_hex(random_bytes)
|
return str.to_hex(random_bytes)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- 存储授权码(有效期5分钟)
|
-- 存储授权码(有效期5分钟)
|
||||||
function _M.create(user_id, client_id, redirect_uri, scope)
|
function _M.create(user_id, client_id, redirect_uri, scope)
|
||||||
local code = generate_code()
|
local code = generate_code()
|
||||||
print("authorize code:", code)
|
|
||||||
local code_key = "auth_code-"..code
|
local code_key = "auth_code-"..code
|
||||||
local code_data = cjson.encode({
|
local code_data = cjson.encode({
|
||||||
user_id = user_id,
|
user_id = user_id,
|
||||||
|
|
@ -47,11 +45,9 @@ function _M.consume(code, client_id)
|
||||||
shared_dict:delete(code_key)
|
shared_dict:delete(code_key)
|
||||||
|
|
||||||
local code_data = cjson.decode(data)
|
local code_data = cjson.decode(data)
|
||||||
--[[
|
|
||||||
if code_data.client_id ~= client_id then
|
if code_data.client_id ~= client_id then
|
||||||
return nil, "客户端不匹配"
|
return nil, "客户端不匹配"
|
||||||
end
|
end
|
||||||
--]]
|
|
||||||
if code_data.expires_at < ngx.time() then
|
if code_data.expires_at < ngx.time() then
|
||||||
return nil, "授权码已过期"
|
return nil, "授权码已过期"
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -93,66 +93,4 @@ function _M.authorizationToken(auth_header)
|
||||||
return response
|
return response
|
||||||
end
|
end
|
||||||
|
|
||||||
local access_token_ttl = 10 * 60 --十分钟
|
|
||||||
local refresh_token_ttl = 7 * 24 * 3600 --7天
|
|
||||||
local id_token_ttl = 60 * 60 --1小时
|
|
||||||
|
|
||||||
-- 生成 Access Token(简化为 JWT 格式)
|
|
||||||
function _M.generate_access_token(priv_key, sub, client_id, scope)
|
|
||||||
local now = ngx.time()
|
|
||||||
local payload = {
|
|
||||||
--iss = OP_DOMAIN,
|
|
||||||
sub = sub,
|
|
||||||
client_id = client_id,
|
|
||||||
exp = now + access_token_ttl,
|
|
||||||
iat = now,
|
|
||||||
scope = scope, --"openid profile email"
|
|
||||||
jti = ngx.md5(now .. math.random() .. client_id) -- 唯一标识
|
|
||||||
}
|
|
||||||
local access_token = jwt:sign(priv_key, {
|
|
||||||
header = { typ = "JWT", alg = "HS256" },
|
|
||||||
payload = payload
|
|
||||||
})
|
|
||||||
return access_token
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 生成 refresh Token(简化为 JWT 格式)
|
|
||||||
function _M.generate_refresh_token(priv_key, sub, client_id, scope)
|
|
||||||
local now = ngx.time()
|
|
||||||
local payload = {
|
|
||||||
--iss = OP_DOMAIN,
|
|
||||||
sub = sub,
|
|
||||||
client_id = client_id,
|
|
||||||
exp = now + refresh_token_ttl,
|
|
||||||
iat = now,
|
|
||||||
scope = scope, --"openid profile email"
|
|
||||||
jti = ngx.md5(now .. math.random() * 1000 .. client_id)
|
|
||||||
}
|
|
||||||
local refresh_token = jwt:sign(priv_key, {
|
|
||||||
header = { typ = "JWT", alg = "HS256" },
|
|
||||||
payload = payload
|
|
||||||
})
|
|
||||||
return refresh_token
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 生成 ID Token(JWT)
|
|
||||||
function _M.generate_id_token(priv_key, sub, client_id, userinfo, scope)
|
|
||||||
local now = ngx.time()
|
|
||||||
local payload = {
|
|
||||||
--iss = OP_DOMAIN, -- issuer:OP 域名
|
|
||||||
sub = sub, -- subject:用户唯一标识
|
|
||||||
aud = client_id, -- audience:客户端 ID
|
|
||||||
exp = now + id_token_ttl, -- 过期时间(1小时)
|
|
||||||
iat = now, -- 签发时间
|
|
||||||
nonce = ngx.var.nonce, -- 可选:防重放攻击
|
|
||||||
--name = userinfo.name,
|
|
||||||
--email = userinfo.email
|
|
||||||
}
|
|
||||||
local id_token = jwt:sign(priv_key, {
|
|
||||||
header = { typ = "JWT", alg = "HS256" }, -- 算法可选 HS256/RS256
|
|
||||||
payload = payload
|
|
||||||
})
|
|
||||||
return id_token
|
|
||||||
end
|
|
||||||
|
|
||||||
return _M
|
return _M
|
||||||
Loading…
Reference in New Issue
Block a user