使用FastAPI和Swagger刷新令牌

问题描述

我正在尝试使用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的用户界面在需要刷新时更新承载令牌,而又不让用户再次登录

解决方法


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


用例:Swagger UI 需要使用更新的 JWT 令牌自动刷新,而无需关闭 UI。

系统/应用程序:

  • 钥匙斗篷
  • 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,刷新或关闭/重新打开页面将保留授权。

根据评论尚不清楚 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


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