【问题标题】:Refresh token using FastAPI and Swagger使用 FastAPI 和 Swagger 刷新令牌
【发布时间】:2021-01-03 04:25:52
【问题描述】:

我正在尝试使用 FastAPI 为我们的组织创建一个 API。它有一个用于所有身份验证的 KeyCloak 服务器,以及被认为是最佳实践的 OpenID Connect 和 JWT。

在最简单的情况下,其他人负责获取有效的 JWT 令牌,以便 FastAPI 可以简单地解码和读取用户和权限。

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

async def get_current_user(token: str = Depends(oauth2_scheme)):

    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )

    try:
        jwt_token = jwt.decode(token, key=env.keycloak_server_public_key, audience='myorg')
        return jwt_token['preferred_username']
    except jwt.exceptions.ExpiredSignatureError:
        raise credentials_exception

生活很简单!

不过,我确实想让用户使用 Swagger 页面探索 API。我创建了这个功能,让用户可以使用 UI 登录:

@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    login_request = requests.post(
        "https://mygreatorg.com/auth/realms/master/protocol/openid-connect/token",
        data={
            "grant_type": "password",
            "username": form_data.username,
            "password": form_data.password,
            "client_id": "fastapi-application",
        },
    )
    raw_response = json.loads(login_request.content.decode('utf-8'))
    raw_response['acquire_time'] = time.time()

    TOKEN_CACHE[form_data.username] = raw_response

    return {"access_token": raw_response['access_token'], "token_type": "bearer"}

这很好用。 Swagger 中的 auth 标头现在是令牌,它会验证大约一分钟。令牌的过期时间设置为非常短的时间。然后预计使用raw_response 有效负载中提供的 refresh_token 刷新它们。

在给定 refresh_token 的情况下,我可以很容易地发出另一个请求以获取新的有效访问令牌。但我无法让 Swagger 在 UI 中更改请求的令牌。我发现的唯一方法是注销并重新登录,但如果他们只允许一分钟而不被踢出,用户会非常恼火。

一种解决方法是简单地缓存令牌并忽略过期时间,让用户登录一段时间,但这违背了整个安全设置的目的,感觉是个坏主意。

关于如何让 FastAPI 的 UI 在需要刷新时更新不记名令牌而不让用户再次登录的任何想法?

【问题讨论】:

  • 你找到解决办法了吗?
  • 我还没有找到解决这个问题的方法,但是自从我在发布问题后不久就离开了工作场所以来,我一直没有积极寻找。
  • 我之前已经实现了类似的东西,你能否给我更多关于你可以访问的 API 端点的信息。比如/token/grant_type: refresh_token等等。我之前没用过Open ID,如果你能指点我一些阅读材料,我可以帮你看看它
  • 这个issue很好的描述了这个问题。 github.com/swagger-api/swagger-ui/issues/7257
  • 你试过return login_request.json()。登录请求应该带有一个刷新令牌,没有它你不能刷新 access_token。

标签: python jwt swagger swagger-ui fastapi


【解决方案1】:

这远非一个答案,我可能会在稍后删除它。它只是概述我对这个问题的研究的一个占位符


用例: Swagger UI 需要在不关闭 UI 的情况下使用更新的 JWT 令牌自动刷新。

系统/应用程序:

  • 钥匙斗篷
  • FastApi
  • 大摇大摆
  • OpenID Connect 和 JWT

当我研究这个问题时,我注意到这个问题中的问题在 FastApi 和 Swagger 的问题中都有提出。

大摇大摆


在查看 Swagger 的代码库时,我注意到一个名为 persistAuthorization 的授权参数。根据文档,此参数将维护授权数据,并且此数据不会在浏览器关闭/刷新时丢失。

在 Swagger 代码库中我看到了这个项目:

  # source: /src/plugins/topbar/topbar.jsx
  #
  flushAuthData() {
    const { persistAuthorization } = this.props.getConfigs()
    if (persistAuthorization)
    {
      return
    }
    this.props.authActions.restoreAuthorization({
      authorized: {}
    })
  }

上面的代码调用了 /src/core/plugins/auth/actions.js

在 Swagger 拉取请求中有一个名为 configs.preserveAuthorization 的待处理功能此功能的范围:

如果我们将 configs.preserveAuthorization 设置为 true,则刷新或关闭/重新打开页面将保留授权。

根据 cmets 并不清楚 preserveAuthorizationpersistAuthorization 的功能有何不同。

FastApi


当我查看 FastApi 代码库时,我注意到一个名为 refreshUrlOAuthFlowsMo​​del。我浏览了 FastApi 文档并没有看到提到这一点。

# source: /fastapi/security/oauth2.py
#
class OAuth2AuthorizationCodeBearer(OAuth2):
    def __init__(
        self,
        authorizationUrl: str,
        tokenUrl: str,
        refreshUrl: Optional[str] = None,
        scheme_name: Optional[str] = None,
        scopes: Optional[Dict[str, str]] = None,
        auto_error: bool = True,
    ):
        if not scopes:
            scopes = {}
        flows = OAuthFlowsModel(
            authorizationCode={
                "authorizationUrl": authorizationUrl,
                "tokenUrl": tokenUrl,
                "refreshUrl": refreshUrl,
                "scopes": scopes,
            }
        )
        super().__init__(flows=flows, scheme_name=scheme_name, auto_error=auto_error)

    async def __call__(self, request: Request) -> Optional[str]:
        authorization: str = request.headers.get("Authorization")
        scheme, param = get_authorization_scheme_param(authorization)
        if not authorization or scheme.lower() != "bearer":
            if self.auto_error:
                raise HTTPException(
                    status_code=HTTP_401_UNAUTHORIZED,
                    detail="Not authenticated",
                    headers={"WWW-Authenticate": "Bearer"},
                )
            else:
                return None  # pragma: nocover
        return param

查看 FastApi 的问题时,我注意到有人要求添加 OAuth2RerefreshRequestForm。此问题的范围是令牌刷新。

我还注意到另一个问题refresh token with Keycloak and Fastapi


对于无法提供可靠的答案,我深表歉意。

【讨论】:

  • 请留下这个答案,不要删除...有帮助
猜你喜欢
  • 2020-10-06
  • 2021-01-29
  • 2020-06-12
  • 1970-01-01
  • 2019-06-29
  • 2022-10-31
  • 2020-07-12
  • 2020-05-29
  • 1970-01-01
相关资源
最近更新 更多