问题描述
我正在尝试使用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,刷新或关闭/重新打开页面将保留授权。
根据评论尚不清楚 preserveAuthorization 和 persistAuthorization 功能有何不同。
FastApi
当我查看 FastApi 代码库时,我注意到一个名为 refreshUrl 的 OAuthFlowsModel。我浏览了 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
对于无法提供可靠的答案,我深表歉意。