JWT cookie 需要是什么样子才能与 NGINX 模块一起使用?

What does a JWT cookie need to look like to work with NGINX modules?

我一直在使用 NGINX 作为反向代理,最近决定我需要为网站上的路由添加身份验证。我意识到有多个 NGINX 模块可以让我通过 NGINX 处理身份验证(参见下面的链接)。所以,我构建了一个集成 auth0 的单点登录页面来测试它是如何工作的。

所有模块都是相似的,并且允许您指定一个 auth_jwt_key(用于验证 JWT)以及一个用于存储 JWT (auth_jwt) 的变量。我决定将 JWT 存储在 cookie 中。

不幸的是,我无法通过 NGINX 进行验证并继续看到 401 unauthorized return 代码。

这是 flask 应用程序的一部分,我在其中处理 auth0 登录并将 JWT 存储到 cookie 中:

@app.route('/callback')
    def callback_handling():
    token = auth0.authorize_access_token()
    response = redirect('/dashboard')
    response.set_cookie('lt_jwt', value=token.get('id_token'), max_age=token.get('expires_in'))
    return response

你能看出这有什么问题吗?生成的 cookie 看起来像这样(为了便于阅读,我删除了大部分):lt_jwt eyJ0eX[...]SkRNZyJ9.eyJnaXZ[...]kzNDV9.d3Tzr[...]NzbA staging-auth0-login.scapp.io / 9/13/2018, 1:55:45 PM 1.03 KB

我可以将 cookie 值放入 jwt.io 并正确解码,但我的问题是提到的 NGINX 模块解码有问题。

这是一个 NGINX 配置示例,我在其中设置身份验证:

location = /dashboard {
    auth_jwt_key "AUTH0_CLIENT_SECRET";
    auth_jwt $cookie_lt_jwt;

    root /usr/src/lt/nginx;
    try_files /dashboard.html =404;
}

基本上,我从来没有看到 dashboard.html 而总是看到 401 unauthorized。 NGINX error.log 显示解码 JWT 失败:[warn] 64#64: *23 JWT: failed to parse jwt,在本例中是来自我使用的自定义 nginx 模块的错误日志:

// Validate the jwt
if (jwt_decode(&jwt, jwt_data, conf->jwt_key.data, conf->jwt_key.len))
{
  ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "JWT: failed to parse jwt");
  return NGX_HTTP_UNAUTHORIZED;
}

参考:https://github.com/maxx-t/nginx-jwt-module/blob/d9a2ece81ca66647f81fc2586b29b348af67f8aa/src/ngx_http_auth_jwt_module.c#L124

不幸的是,调试它并不容易,但我从另一个我也测试过的自定义 NGINX 模块收到了类似的响应:jwt_verify: error on decode: SUCCESS,这是此代码段的结果:

  jwt_t* token;
  int err = jwt_decode(&token, token_data, alcf->key.data, alcf->key.len);
  if (err) {
    ngx_log_error(NGX_LOG_ERR, r->connection->log, errno,
                  "jwt_verify: error on decode: %s", strerror(errno));
    return ngx_http_auth_jwt_set_realm(r, &alcf->realm);
  }

参考:https://github.com/tizpuppi/ngx_http_auth_jwt_module/blob/bf8ae5fd4b8e981b7683990378356181dee93842/ngx_http_auth_jwt_module.c#L247

所以在这两种情况下 jwt_decode 都被调用并失败(即使它的错误代码显然是 SUCCESS)。

我在这里问的原因是我觉得我在这里可能在概念上做错了:

  1. 正在格式化 cookie(我见过 jwt cookie 看起来像这样: Bearer eyJ0eX[...]SkRNZyJ9.eyJnaXZ[...]kzNDV9.d3Tzr[...]NzbA
  2. 假设 auth0 生成的令牌可以这样使用
  3. ...?

如果您对 NGINX + auth0 有任何见解或良好的工作示例,请告诉我。我已经阅读了 auth0 的这篇文章 https://auth0.com/blog/use-nginx-plus-and-auth0-to-authenticate-api-clients/,详细介绍了如何使用非常相似的 NGINX Pro 模块,但我无权访问该商业模块。

回答主要问题:cookie 应该只包含没有任何前缀的 JWT。问题中的 python(烧瓶)代码没有做错任何事情,我能够通过 curl 确认您实际上可以获得存储在 cookie 中的授权(使用有效的 JWT):

curl https://some.page.com/application --cookie "lt_jwt=eyJ0eX[...]SkRNZyJ9.eyJnaXZ[...]kzNDV9.d3Tzr[...]NzbA"

那么这里的问题是什么 - 为什么我不能在浏览器中进行身份验证,当它通过 curl 工作时?

原因在于 NGINX 配置,它要求在 http 上下文中禁用身份验证。这本质上是 NGINX 模块中的一个错误,此后开发人员设法修复了该错误。

经验教训:这通常不是你的错 ;)