Django와 Flask 프레임워크와 Starlette 기반 프레임워크의 차이점은 후자가 비동기식이라는 것이다.
create OAuth instance
from authlib.integrations.starlette_client import OAuth
oauth = OAuth()
from starlette.config import Config
config = Config('.env')
oauth = OAuth(config)
# google을 등록할 때, 환경으로부터 GOOGLE_CLIENT_ID와 GOOGLE_CLIENT_SECRET을 로드하여 사용
oauth.register(name='google', ...)
oauth.register(
'google',
client_id='...',
client_secret='...',
...
)
from starlette.routing import Route
# Google 로그인을 위한 라우트
async def login_via_google(request):
google = oauth.create_client('google')
redirect_uri = request.url_for('authorize_google')
return await google.authorize_redirect(request, redirect_uri)
# Google 인증을 위한 라우트
async def authorize_google(request):
google = oauth.create_client('google')
token = await google.authorize_access_token(request)
# 토큰 및 사용자 정보와 관련된 작업 수행
return '...'
# Starlette 앱에 라우트 추가
routes = [
Route('/login/google', login_via_google),
Route('/auth/google', authorize_google)
]
.register를 할 때 openid 범위(scope)를 추가하기만 하면 된다. id_token을 파싱하고 userinfo를 가져올 수 있다.oauth.register(
'google',
...
server_metadata_url='https://accounts.google.com/.well-known/openid-configuration',
client_kwargs={'scope': 'openid profile email'}
)
token = await oauth.google.authorize_access_token()
id_token이 있어야 하며 Authlib에서는 .parse_id_token을 자동으로 호출했으므로, 토큰에서 userinfo를 가져올 수 있다.userinfo = token['userinfo']
import json
from starlette.config import Config
from starlette.applications import Starlette
from starlette.middleware.sessions import SessionMiddleware
from starlette.responses import HTMLResponse, RedirectResponse
from authlib.integrations.starlette_client import OAuth
app = Starlette(debug=True)
app.add_middleware(SessionMiddleware, secret_key="!secret")
config = Config('.env')
oauth = OAuth(config)
CONF_URL = 'https://accounts.google.com/.well-known/openid-configuration'
oauth.register(
name='google',
server_metadata_url=CONF_URL,
client_kwargs={
'scope': 'openid email profile',
'prompt': 'select_account', # force to select account
}
)
@app.route('/')
async def homepage(request):
user = request.session.get('user')
if user:
data = json.dumps(user)
html = (
f'<pre>{data}</pre>'
'<a href="/logout">logout</a>'
)
return HTMLResponse(html)
return HTMLResponse('<a href="/login">login</a>')
@app.route('/login')
async def login(request):
redirect_uri = request.url_for('auth')
return await oauth.google.authorize_redirect(request, redirect_uri)
@app.route('/auth')
async def auth(request):
token = await oauth.google.authorize_access_token(request)
user = token.get('userinfo')
if user:
request.session['user'] = user
return RedirectResponse(url='/')
@app.route('/logout')
async def logout(request):
request.session.pop('user', None)
return RedirectResponse(url='/')
if __name__ == '__main__':
import uvicorn
uvicorn.run(app, host='127.0.0.1', port=8000)