Der Server, der den Benutzer (über /login) zum Identitätsanbieter umleitet, ist möglicherweise nicht derselbe, der die /auth-Route ausführt.
Ich kann möglicherweise die Umleitungs-URL mithilfe der IP-Adresse des Servers erstellen, der die /login-Anfrage ausführt, aber das klingt für mich nicht richtig, insbesondere für die von Keycloak zugelassenen Umleitungs-URLs, die wären statische IPs.
Hier ist ein Codeausschnitt, den ich geschrieben habe:
Code: Select all
oauth = OAuth()
oauth.register(
name="keycloak",
client_id=settings.keycloak.client_id,
client_secret=settings.keycloak.client_secret.get_secret_value(),
server_metadata_url=settings.keycloak.server_metadata_url,
# The group scope does not exist by default. This must be added.
client_kwargs={"scope": "openid email profile group"},
# The state is a value which is used as a kind of CSRF check.
# When the /login redirects to keycloak, it includes this value.
# Later, when keycloak redirects to /auth, it also includes the state value.
# If the values mismatche, a CSRF error is raised.
# Configuring it is required to perform replication.
state="toto",
)
oauth_client: StarletteOAuth2App = oauth.keycloak
def get_user_name(userinfo: dict):
"""Get the user name from user information dict."""
return userinfo.get("name", None) or userinfo.get("preferred_username")
@router.get("/login", tags=["user"])
async def login(request: Request):
"""Redirect the user to keycloak login page."""
redirect_uri = request.url_for("auth")
return await oauth_client.authorize_redirect(request, redirect_uri, state="toto")
@router.get("/auth", tags=["user"])
async def auth(request: Request):
"""Authenticate the user by creating a session cookie."""
token = await oauth_client.authorize_access_token(request)
userinfo = token["userinfo"]
# Needs json.dumps otherwise this is not correctly saved in session
request.session["user"] = json.dumps(userinfo)
_LOGGER.info("User %s got connected", get_user_name(userinfo))
# Get the URL the user requested before login, if any.
target_url = request.session.pop("target-url", "/")
return RedirectResponse(target_url)
Die Schlüsselfrage könnte der Wert des Status-Parameters sein, der auf allen Servern gleich sein sollte. Allerdings ist in der Dokumentation nicht klar, wie man es benutzt. Außerdem weist diese Antwort darauf hin, dass der Wert zufällig sein sollte, um Angriffe zu verhindern. Also, wie könnte ich das tun?
Mobile version