From 992e11ae6a0fd2197fe2b4e6e9745bb4c3c1ada6 Mon Sep 17 00:00:00 2001 From: xtaodada Date: Mon, 20 May 2024 22:12:36 +0800 Subject: [PATCH] :sparkles: Support openID AutoDiscovery URL --- .env.example | 1 + README.md | 3 ++- src/oauth2/endpoints.py | 20 ++++++++++++++++++++ src/oauth2/models.py | 18 +++++++++++++++++- src/oauth2/storage.py | 5 ++++- 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/.env.example b/.env.example index 2c5c29d..e4afe26 100644 --- a/.env.example +++ b/.env.example @@ -2,6 +2,7 @@ CONN_URI=sqlite+aiosqlite:///data/db.sqlite3 DEBUG=True PROJECT_URL=http://127.0.0.1 PROJECT_LOGIN_SUCCESS_URL=http://google.com +PROJECT_HOST=127.0.0.1 PROJECT_PORT=80 JWT_PRIVATE_KEY='data/private_key' JWT_PUBLIC_KEY='data/public_key' diff --git a/README.md b/README.md index c54138c..200c996 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@ CONN_URI=sqlite+aiosqlite:///data/db.sqlite3 # 数据库 uri DEBUG=True # 调试模式 PROJECT_URL=http://127.0.0.1 # 项目可访问的地址 -PROJECT_LOGIN_SUCCESS_URL=http://google.com # 登录成功后跳转的地址 +PROJECT_LOGIN_SUCCESS_URL=http://google.com # 默认登录成功后跳转的地址 +PROJECT_HOST=127.0.0.1 # 项目监听的 ip 地址 PROJECT_PORT=80 # 项目运行的端口 JWT_PRIVATE_KEY='data/private_key' # jwt 私钥 JWT_PUBLIC_KEY='data/public_key' # jwt 公钥 diff --git a/src/oauth2/endpoints.py b/src/oauth2/endpoints.py index 4acb3ce..623e8d2 100644 --- a/src/oauth2/endpoints.py +++ b/src/oauth2/endpoints.py @@ -5,6 +5,7 @@ from aioauth.server import AuthorizationServer from fastapi import APIRouter, Depends, Request from aioauth_fastapi.utils import to_fastapi_response, to_oauth2_request +from .models import Configuration from .storage import Storage from ..config import settings as local_settings from ..storage.sqlalchemy import SQLAlchemyStorage, get_sqlalchemy_storage @@ -52,5 +53,24 @@ async def authorize( @router.get("/keys") +@router.get("/.well-known/jwks.json") async def keys(): return get_pub_key_resp() + + +@router.get("/.well-known/openid-configuration") +async def get_configuration(): + return Configuration( + issuer=local_settings.PROJECT_URL, + authorization_endpoint=f"{local_settings.PROJECT_URL}/oauth2/authorize", + token_endpoint=f"{local_settings.PROJECT_URL}/oauth2/token", + userinfo_endpoint="", + revocation_endpoint="", + jwks_uri=f"{local_settings.PROJECT_URL}/oauth2/.well-known/jwks.json", + scopes_supported=["openid", "profile", "email"], + response_types_supported=["code"], + grant_types_supported=["authorization_code", "refresh_token"], + subject_types_supported=["public"], + id_token_signing_alg_values_supported=["RS256"], + claims_supported=["username", "email"], + ) diff --git a/src/oauth2/models.py b/src/oauth2/models.py index 4a16aad..c8926b2 100644 --- a/src/oauth2/models.py +++ b/src/oauth2/models.py @@ -1,5 +1,6 @@ -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING, Optional, List +from pydantic import BaseModel from pydantic.types import UUID4 from sqlmodel.main import Field, Relationship @@ -48,3 +49,18 @@ class Token(BaseTable, table=True): # type: ignore user_id: UUID4 = Field(foreign_key="users.id", nullable=False) user: "User" = Relationship(back_populates="user_tokens") + + +class Configuration(BaseModel): + issuer: str + authorization_endpoint: str + token_endpoint: str + userinfo_endpoint: str + revocation_endpoint: str + jwks_uri: str + scopes_supported: List[str] + response_types_supported: List[str] + grant_types_supported: List[str] + subject_types_supported: List[str] + id_token_signing_alg_values_supported: List[str] + claims_supported: List[str] diff --git a/src/oauth2/storage.py b/src/oauth2/storage.py index d008a2a..3e09b4e 100644 --- a/src/oauth2/storage.py +++ b/src/oauth2/storage.py @@ -276,7 +276,10 @@ class Storage(BaseStorage): ) -> str: scopes = enforce_list(scope) user = await self.get_user(request) - user_data = {} + user_data = { + "aud": client_id, + "iss": settings.PROJECT_URL, + } if "email" in scopes: user_data["email"] = user.username