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;
}
不幸的是,调试它并不容易,但我从另一个我也测试过的自定义 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);
}
所以在这两种情况下 jwt_decode
都被调用并失败(即使它的错误代码显然是 SUCCESS
)。
我在这里问的原因是我觉得我在这里可能在概念上做错了:
- 正在格式化 cookie(我见过 jwt cookie 看起来像这样:
Bearer eyJ0eX[...]SkRNZyJ9.eyJnaXZ[...]kzNDV9.d3Tzr[...]NzbA
- 假设 auth0 生成的令牌可以这样使用
- ...?
如果您对 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 模块中的一个错误,此后开发人员设法修复了该错误。
经验教训:这通常不是你的错 ;)
我一直在使用 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;
}
不幸的是,调试它并不容易,但我从另一个我也测试过的自定义 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);
}
所以在这两种情况下 jwt_decode
都被调用并失败(即使它的错误代码显然是 SUCCESS
)。
我在这里问的原因是我觉得我在这里可能在概念上做错了:
- 正在格式化 cookie(我见过 jwt cookie 看起来像这样:
Bearer eyJ0eX[...]SkRNZyJ9.eyJnaXZ[...]kzNDV9.d3Tzr[...]NzbA
- 假设 auth0 生成的令牌可以这样使用
- ...?
如果您对 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 模块中的一个错误,此后开发人员设法修复了该错误。
经验教训:这通常不是你的错 ;)