在Nginx中增加对OAuth协议的支持的教程

2019-10-17 20:14:03刘景俊

local args = ngx.req.get_uri_args()
if args.error and args.error == "access_denied" then
    ngx.status = ngx.HTTP_UNAUTHORIZED
    ngx.say("{"status": 401, "message": ""..args.error_description..""}")
    return ngx.exit(ngx.HTTP_OK)
end

现在我们解决了基本的错误情况,我们要为访问令牌设置cookie。在我的例子中,cookie会在访问令牌过期前过期,所以我可以利用cookie来刷新访问令牌。

local access_token = ngx.var.cookie_SGAccessToken
if access_token then
    ngx.header["Set-Cookie"] = "SGAccessToken="..access_token.."; path=/;Max-Age=3000"
end

现在,我们解决了错误响应的api,并储存了access_token供后续访问。我们现在需要确保OAuth认证过程正确启动。下面,我们想要:

    如果没有access_token已经或将要存储,开启OAuth认证     如果query string的参数中有OAuth访问代码(access code),使用OAuth API检索用户的access_token     拒绝使用非法访问代码用户的请求

阅读nginx-Lua函数和变量的相关文档可以解决一些问题,或许还能告诉你访问特定请求/响应信息的各种方法。

此时,我们需要从我们的api接口获取一个TOKEN。nginx-lua提供了ngx.location.capture方法,支持发起一个内部请求到redis,并接收响应。这意味着,我们不能直接调用类似于http://seatgeek.com/ncaa-football-tickets,但我们可以用proxy_pass把这种外部链接包装成内部请求。

我们通常约定给这样的内部请求前面加一个_(下划线), 用来阻止外部直接访问。

-- 第一步,从api获取获取token
if not access_token or args.code then
    if args.code then
        -- internal-oauth:1337/access_token
        local res = ngx.location.capture("/_access_token?client_id="..app_id.."&client_secret="..app_secret.."&code="..args.code)

        -- 终止所有非法请求
        if res.status ~= 200 then
            ngx.status = res.status
            ngx.say(res.body)
            ngx.exit(ngx.HTTP_OK)
        end

        -- 解码 token
        local text = res.body
        local json = cjson.decode(text)
        access_token = json.access_token
    end

    -- cookie 和 proxy_pass token 请求失败