让 grafana 使用现有的 JWT 令牌

Posted

技术标签:

【中文标题】让 grafana 使用现有的 JWT 令牌【英文标题】:Make grafana use existing JWT token 【发布时间】:2022-01-02 02:08:19 【问题描述】:

我有一个具有 JWT 身份验证的 React + DRF Web 应用程序,我在其中使用 djangorestframework-simplejwt。

我在 localStorage 中存储访问和刷新令牌。是否可以使用这些令牌在 Grafana 中进行身份验证?如果是,我该怎么做?当我导航到 /grafana(使用 nginx 帮助)时,我希望通过在必要时为 Grafana 创建用户来查看我的应用程序中的用户登录到 Grafana。

【问题讨论】:

【参考方案1】:

不清楚什么是“JWT 身份验证”以及 JWT 是如何创建的。我猜它来自 Open ID Connect 身份验证,因此没有什么能阻止您将 Grafana OIDC auth 与相同的 OIDC 身份提供程序一起使用,以获得无缝的用户单点登录体验。

【讨论】:

这不是 OIDC,我想它比那更简单。我应该更改身份验证方法吗?【参考方案2】:

让我为那些寻求解决在他们的应用程序和 Grafana 中使用通用 JWT 的问题的人解释所有细节。如果您只关心 Grafana 方面,则可以跳过开头:

反应方:

我有一个 Django REST Framework API 和 React UI。当一个令牌返回给用户时,React UI 将它保存到本地存储中。我为按钮实现了一个 onClick 处理程序以导航到 Grafana,如下所示:
// read token value from local storage
const refToken = localStorage.getItem("refresh_token");
window.location.href = `/grafana/login/?mytoken=$refToken`;

Django REST 框架端(djangorestframework-simplejwt):

API 可以使用 RS256 签名算法生成和验证 JWT 令牌。由于 RSA,API 需要生成 2 个密钥,私钥和公钥。我用jwcrypto 生成了那些。我用私钥.pem的内容设置SIGNING_KEY,用公钥.pem的内容设置VERIFYING_KEY
from jwcrypto import jwk
import uuid

keyid = str(uuid.uuid4())
key = jwk.JWK.generate(kty='RSA', alg='RS256', size=2048, kid=keyid, use='sig')

# export to PEM files
priv_pem = key.export_to_pem(private_key=True, password=None)
pub_pem = key.export_to_pem()

with open("rsa_pub.pem", "wb") as f:
    f.write(pub_pem)

with open("rsa.pem", "wb") as f:
    f.write(priv_pem)
SIMPLE_JWT = 
    'ACCESS_TOKEN_LIFETIME': timedelta(hours=1),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
    'SIGNING_KEY': open("/path/to/folder/which/has/keys/rsa.pem").read(),
    'VERIFYING_KEY': open("/path/to/folder/which/has/keys/rsa_pub.pem").read(),
    'ALGORITHM': 'RS256',
    'USER_ID_FIELD': 'username',
    'USER_ID_CLAIM': 'username',
    'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),

Grafana 方面:

为确保此操作有效,您需要为 Grafana 创建具有相同用户名的用户。否则您将收到 Invalid JWT 响应。 auto_sign_up setting is not working for the JWT authentication yet.

然后我为 Grafana 容器添加了这些配置。 header_name 可以是任何字符串,但你也需要在 nginx 端使用它:

version: "3"
services:
  ...
  ...
  grafana:
    image:  grafana/grafana:8.2.2
    volumes:
      - ...
      - "/path/to/folder/which/has/keys:/key_set"
    environment:
      - "GF_SERVER_ROOT_URL=/grafana/"
      - "GF_SERVER_SERVE_FROM_SUB_PATH=true"
      - "GF_AUTH_PROXY_ENABLED=true"
      - "GF_AUTH_PROXY_ENABLE_LOGIN_TOKEN=true"
      - "GF_AUTH_JWT_ENABLED=true"
      - "GF_AUTH_JWT_HEADER_NAME=X-JWT-Assertion"
      - "GF_AUTH_JWT_USERNAME_CLAIM=username"
      - "GF_AUTH_JWT_KEY_FILE=/key_set/rsa_pub.pem"

Nginx 端:

location /grafana/ 
    try_files /dev/null @proxy_grafana;


location /grafana/login/ 
    try_files /dev/null @proxy_grafana_login;


location @proxy_grafana 
    ...
    proxy_pass   http://grafana:3000;


location @proxy_grafana_login 
    ...
    proxy_set_header X-JWT-Assertion "$arg_mytoken";
    proxy_pass   http://grafana:3000;

【讨论】:

刷新令牌不用于身份验证。为什么不使用访问令牌? 访问令牌的有效期很短,我认为在我向 grafana 进行身份验证后可能会很糟糕。在应用程序中,我可以控制访问令牌并在需要时刷新它。 这是设计使然。访问令牌的有效期很短,刷新令牌用于更新访问令牌。 我知道。这是我想避免的。我不希望令牌在浏览 grafana 时过期。如果我在 grafana 中选择刷新令牌进行身份验证,那么我的应用程序和 grafana 将一起过期。至少,这是我的目标。

以上是关于让 grafana 使用现有的 JWT 令牌的主要内容,如果未能解决你的问题,请参考以下文章

Grafana:如何使用 JWT 身份验证?

Sails JS - 删除现有的 JWT

JWT 身份验证:使用 UI 令牌对 Graphene/Django (GraphQL) 查询进行身份验证?

使用 Knock gem 生成 JWT 令牌时出现 500 内部服务器错误

在 Python 中使用来自 Gravitee 的公钥解码 JWT 令牌时出现问题

使用 php-jwt 库解码 firebase 自定义令牌时出现 openssl_verify() 错误