diff --git a/src/dao/oauth/oauth.lua b/src/dao/oauth/oauth.lua index da120d8..32d945a 100644 --- a/src/dao/oauth/oauth.lua +++ b/src/dao/oauth/oauth.lua @@ -8,6 +8,29 @@ local applicationDao = require("dao.system.application") local _M = {} +--通过用户名和密码进行认证 +function _M.authenticateUserPasswd(username, passwd) + --验证用户名是否为空 + local code, res = userDao:getUserByUsername(username) --authenticate(name, passwd) + if code ~= 0 then + return 0x000001, res + end + local num = 0 + if res ~= nil then + num = table.getn(res) + end + --用户不存在时返回 + if num <= 0 then + return 0x01000C,nil + end + --进行密码验证 获取数据库的密码 + local pwdMd5 = ngx.md5(res[1].password) + if pwdMd5 ~= passwd then + return 0x000001,res --密码错误 + end + return 0, res +end + --用户登录业务逻辑处理 function _M.login(jsonData) --解析json中的键和数据值 @@ -65,4 +88,9 @@ function _M.getApplicationBy(client_id, redirect_uri) return applicationDao.getApplicationByClientId(client_id, redirect_uri) end +function _M.getApplicationByUserid(user_id, client_id, client_secret) + --print("getApplicationBy user_id:", user_id, " client_id:", client_id, "client_secret", client_secret) + return applicationDao.getApplicationByUserid(user_id, client_id, client_secret) +end + return _M \ No newline at end of file diff --git a/src/dao/system/application.lua b/src/dao/system/application.lua index 73a6f48..f7cb4a0 100644 --- a/src/dao/system/application.lua +++ b/src/dao/system/application.lua @@ -110,4 +110,10 @@ function _M.getApplicationByClientId(client_id, redirect_uri) return applicationModel:where('app_id', '=', client_id):where('redirect_uris', '=', redirect_uri):get() end +function _M.getApplicationByUserid(user_id, client_id, client_secret) + local sql = [[SELECT "A".user_id,"B".* FROM sys_user_application AS "A" INNER JOIN sys_application AS "B" ON "A".application_id = "B"."id" + WHERE "A".user_id =']]..user_id..[[' AND "B".client_id=']]..client_id..[[' AND "B".client_secret=']]..client_secret.."'" + return applicationModel:exec(sql) +end + return _M \ No newline at end of file diff --git a/src/service/oauth/oauth.lua b/src/service/oauth/oauth.lua index e8b2083..4b167f0 100644 --- a/src/service/oauth/oauth.lua +++ b/src/service/oauth/oauth.lua @@ -77,10 +77,107 @@ function _M:authorize() rest.state = args.state local result = resp:json(ngx.HTTP_OK, rest) resp:send(result) - return end ---根据授权码获取Access-Token +-- 通过用户名认证用户和应用是否存在状态 +local function authorizatePassword(args) + -- 1.校验必填参数验证数据是否符合json + local ok = validator.validateLogin(args) + if not ok then + local result = resp:json(0x000001) + resp:send(result) + return + end + -- 2.验证用户名和密码,应用程序id和应用程序密钥 + local code, res = oauthDao.authenticateUserPasswd(args.username, args.password) + if code ~= 0 or res == nil then + local result = resp:json(0x000001) + resp:send(result) + return + end + -- 3.对当前用户的持有的应用程序进行验证 + local userid = res[1].id + local client_id = args.client_id + local client_secret = args.client_secret + code, res = oauthDao.getApplicationByUserid(userid, client_id, client_secret) + if code ~= 0 or res == nil then + local result = resp:json(0x000001) + resp:send(result) + return + end + local redirect_uri = res[1].redirect_uris + -- 4.生成授权码(随机字符串,确保唯一性)(用户ID、客户端ID、scope、生成时间) + local auth_code, err = authcode.create(userid, client_id, redirect_uri) + if not auth_code then + ngx.log(ngx.ERR, "生成授权码失败: ", err) + ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) + end + -- 5.存储用户信息,证明用户已经登陆 + + -- 6.返回结果 + local rest = {} + rest.redirect_uri = redirect_uri + rest.code = auth_code + local result = resp:json(ngx.HTTP_OK, rest) + resp:send(result) +end + +-- 通过code形式进行认证 +local function authorizateCode(args) + -- 1.校验必填参数验证数据是否符合json + local ok = validator.validateToken(args) + if not ok then + local result = resp:json(0x000001) + resp:send(result) + return + end + -- 2.校验 code 有效性 + local code_data, err = authcode.consume(args.code)--, args.client_id) + if not code_data then + ngx.log(ngx.ERR, "授权码验证失败: ", err) + 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) + local result = resp:json(ngx.HTTP_MOVED_TEMPORARILY, login_url) + resp:send(result) + return + end + -- 4.生成密钥对 + local pub_key, priv_key, err = rsa.generate_rsa_keys(2048) + if err then + print("密钥生成失败: ", err) + local result = resp:json(0x00001) + resp:send(result) + return + end + print("token pubkey:", pub_key) + local user_id = code_data.user_id + local client_id = code_data.client_id + local scope = code_data.scope + -- 5.生成新 Access Token + local new_access_token = token.generate_access_token(priv_key, user_id, client_id, scope) + -- 生成新 Refresh Token(滚动刷新) + local new_refresh_token = token.generate_refresh_token(priv_key, user_id, client_id, scope) + -- 生存id_token + local new_id_token = token.generate_id_token(priv_key, user_id, client_id, scope) + --ngx.say("Generated JWT: ", jwt_obj) + -- 6.返回结果 + local ret = {} + ret.access_token = new_access_token + ret.token_type = "Bearer" + ret.expires_in = 10 * 60 + ret.refresh_token = new_refresh_token + ret.id_token = new_id_token + local result = resp:json(ngx.HTTP_OK, ret) + resp:send(result) +end + +-- 根据授权码获取Access-Token function _M:token() -- 1. 解析请求参数(支持 form-data 和 json) local content_type = ngx.req.get_headers()["Content-Type"] or "" @@ -101,61 +198,20 @@ function _M:token() end args = data else - -- 默认解析 form-urlencoded - args = ngx.req.get_post_args() + if ngx.req.get_method() == "POST" then + -- 默认解析 form-urlencoded + args = ngx.req.get_post_args() + elseif ngx.req.get_method() == "GET" then + args = ngx.req.get_uri_args() + end end - -- 2. 校验必填参数验证数据是否符合json - local ok = validator.validateToken(args) - if not ok then - local result = resp:json(0x000001) - resp:send(result) - return + local grant_type = args.grant_type + if grant_type == "password" then + authorizatePassword(args) + elseif grant_type == "authorization_code" then + authorizateCode(args) end - -- 3. 校验 code 有效性 - local code_data, err = authcode.consume(args.code)--, args.client_id) - if not code_data then - ngx.log(ngx.ERR, "授权码验证失败: ", err) - ngx.exit(ngx.HTTP_BAD_REQUEST) - end - -- 4、验证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) - local result = resp:json(ngx.HTTP_MOVED_TEMPORARILY, login_url) - resp:send(result) - return - end - -- 5. 生成密钥对 - local pub_key, priv_key, err = rsa.generate_rsa_keys(2048) - if err then - print("密钥生成失败: ", err) - local result = resp:json(0x00001) - resp:send(result) - return - end - print("token pubkey:", pub_key) - local user_id = code_data.user_id - local client_id = code_data.client_id - local scope = code_data.scope - -- 6 生成新 Access Token - local new_access_token = token.generate_access_token(priv_key, user_id, client_id, scope) - -- 7 生成新 Refresh Token(滚动刷新) - local new_refresh_token = token.generate_refresh_token(priv_key, user_id, client_id, scope) - -- 8、生存id_token - local new_id_token = token.generate_id_token(priv_key, user_id, client_id, scope) - --ngx.say("Generated JWT: ", jwt_obj) - -- 9. 返回结果 - local ret = {} - ret.access_token = new_access_token - ret.token_type = "Bearer" - ret.expires_in = 10 * 60 - ret.refresh_token = new_refresh_token - ret.id_token = new_id_token - local result = resp:json(ngx.HTTP_OK, ret) - resp:send(result) end --根据Access-Token获取相应用户的账户信息 @@ -188,7 +244,7 @@ function _M:userinfo() resp:send(result) return end - -- 5.对token进行验证 + -- 4.对token进行验证 print("userinfo pubkey:", pub_key) local jwt_obj = jwt:verify(pub_key, token) --如果校验结果中的verified==false,则表示令牌无效 @@ -204,7 +260,7 @@ function _M:userinfo() ngx.status = ngx.HTTP_UNAUTHORIZED ngx.exit(ngx.HTTP_UNAUTHORIZED) end - -- 6.获取token中的信息进行所需用户的信息返回 + -- 5.获取token中的信息进行所需用户的信息返回 local ret = {} ret.sub = 248289761001 ret.name = "Jane Doe" diff --git a/src/util/authcode.lua b/src/util/authcode.lua index d0eaa70..5bd62c8 100644 --- a/src/util/authcode.lua +++ b/src/util/authcode.lua @@ -36,6 +36,9 @@ end -- 验证并消费授权码(一次性有效) function _M.consume(code, client_id) + if code == nil then + return nil, "无效的授权码" + end local code_key = "auth_code-"..code local shared_dict = ngx.shared.codeDict local data = shared_dict:get(code_key) diff --git a/src/validator/oauth/oauth.lua b/src/validator/oauth/oauth.lua index b9e2efd..e7bfb59 100644 --- a/src/validator/oauth/oauth.lua +++ b/src/validator/oauth/oauth.lua @@ -28,6 +28,27 @@ function _M.validateAuthorize(jsonData) return result end +-- 定义一个JSON Schema +local schemaLogin = { + type = "object", + properties = { + grant_type = { type = "string" }, + client_id = { type = "string" }, + client_secret = { type = "string" }, + username = { type = "string" }, + password = { type = "string" }, + }, + required = { "grant_type", "client_id", "client_secret", "username", "password" } +} + +--通过用户名和密码进行认证 +function _M.validateLogin(jsonData) + -- 验证数据是否符合schema + local validator = jsonschema.generate_validator(schemaLogin) + local result = validator(jsonData) + return result +end + local schemaToken = { type = "object", properties = {