简体   繁体   English

使用 FastAPI 和 Swagger 刷新令牌

[英]Refresh token using FastAPI and Swagger

I am trying to create an API for our organization using FastAPI.我正在尝试使用 FastAPI 为我们的组织创建 API。 It has a KeyCloak server that is used for all authentication, and OpenID Connect and JWTs in the way that is considered best practice.它有一个用于所有身份验证的 KeyCloak 服务器,以及被认为是最佳实践的 OpenID Connect 和 JWT。

In the simplest case, someone else takes care of acquiring a valid JWT token so that FastAPI then can simply decode and read the user and permissions.在最简单的情况下,其他人负责获取有效的 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

Life is simple!生活是简单的!

I do, however, want to try to let users explore the API using the Swagger page.但是,我确实想尝试让用户使用 Swagger 页面探索 API。 I have created this function that lets users login using the UI:我创建了这个函数,让用户使用 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"}

This works fine.这工作正常。 The auth header in Swagger is now the token, and it validates, for about a minute. Swagger 中的 auth 标头现在是令牌,它会验证大约一分钟。 The expire time for the tokens is set to a very short time.令牌的过期时间设置为非常短的时间。 One is then expected to refresh them using the refresh_token provided in the raw_response payload.然后期望使用raw_response有效负载中提供的 refresh_token 刷新它们。

I can very easily make another request to get a new valid access token given the refresh_token.给定refresh_token,我可以很容易地发出另一个请求以获取新的有效访问令牌。 But I am unable to get Swagger to change the token of the request in the UI.但是我无法让 Swagger 在 UI 中更改请求的令牌。 The only way I find is to log out and log in again, but users will be very annoyed if they only allow a minute without being kicked out.我找到的唯一方法是注销并重新登录,但是如果他们只允许一分钟而不被踢出,用户会非常生气。

One workaround would be to simply cache the token and ignore the expiration time and let the user be logged in for a while longer, but that defeats the purpose of the entire security setup and feels like a bad idea.一种解决方法是简单地缓存令牌并忽略到期时间并让用户登录一段时间,但这违背了整个安全设置的目的,感觉是个坏主意。

Any ideas on how to let the UI of FastAPI update the bearer token when it needs a refresh, without letting the user log in again?关于如何让 FastAPI 的 UI 在需要刷新时更新不记名令牌而不让用户再次登录的任何想法?


This is far from an answer and I will likely delete this later.这远不是一个答案,我以后可能会删除它。 It is a only a placeholder for outlining my research into this question这是概述我对这个问题的研究的唯一占位符


USE CASE: Swagger UI need to auto refresh with updated JWT token without closing the UI.用例: Swagger UI 需要在不关闭 UI 的情况下使用更新的 JWT 令牌自动刷新。

Systems/Applications:系统/应用:

  • KeyCloak钥匙披风
  • FastApi快速API
  • Swagger昂首阔步
  • OpenID Connect and JWTs OpenID Connect 和 JWT

When I looking into this question I noted that the issue in this question was raised in the issues at both FastApi and Swagger.当我调查这个问题时,我注意到这个问题中的问题是在 FastApi 和 Swagger 的问题中提出的。

Swagger昂首阔步


When looking through the code base of Swagger, I noted an authorization parameter named persistAuthorization .在查看 Swagger 的代码库时,我注意到了一个名为persistAuthorization的授权参数。 According to the documentation this parameter will maintain authorization data and this data will not be lost on browser close/refresh.根据文档,此参数将维护授权数据,并且此数据不会在浏览器关闭/刷新时丢失。

In the Swagger code base I see this item:在 Swagger 代码库中,我看到了这个项目:

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

The code above makes calls to /src/core/plugins/auth/actions.js .上面的代码调用/src/core/plugins/auth/actions.js

In the Swagger pull requests there is a pending feature named configs.preserveAuthorization This scope of this feature:在 Swagger 拉取请求中,有一个名为configs.preserveAuthorization的待处理功能,此功能的范围是:

Refreshing or closing/reopening the the page will preserve authorization if we have configs.preserveAuthorization set to true.如果我们将 configs.preserveAuthorization 设置为 true,刷新或关闭/重新打开页面将保留授权。

It's unclear based on the comments how the features preserveAuthorization and persistAuthorization are different.根据评论,目前还不清楚功能preserveAuthorizationpersistAuthorization 有何不同。

FastApi快速API


When I was looking at the FastApi code base, I noted a OAuthFlowsModel named refreshUrl .当我在看FastApi代码库中,我注意到一个名为refreshUrl OAuthFlowsMo​​del。 I looked through the FastApi document and didn't see this mentioned.我查看了 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

Looking through the issues for FastApi I noted one asking for OAuth2RerefreshRequestForm to be added.查看 FastApi 的问题,我注意到一个要求添加OAuth2RerefreshRequestForm的问题。 The scope of this issue is token refresh.此问题的范围是令牌刷新。

I also noted another issue refresh token with Keycloak and Fastapi我还注意到Keycloak 和 Fastapi 的另一个问题刷新令牌


I apologize for not being able to provide a solid answer.对于无法提供可靠的答案,我深表歉意。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM