我正在使用 Google 帐户为我的网站添加 Oauth 登录,并且偶然发现了一件事 - 如何在执行登录流程之前验证 Oath 提供的信息? ? 首先,我有一个Flask 应用程序以这种方式创建:
是这样实现的:
import logging
import os
from datetime import datetime
from datetime import timedelta
from typing import Any, Dict
import yaml
from flask import Flask, redirect, url_for, g, flash
from flask.typing import ResponseValue
from flask_babel import gettext as _
from flask_login import current_user, logout_user
from werkzeug.wrappers.response import Response
# .. many other local imports ..
def load_config(config_path: str) -> Any:
with open(config_path, 'r', encoding='utf-8') as config_file:
config = yaml.safe_load(config_file)
return config
def create_app(config_path: str = './<path>/config.yaml', config: Any = None) -> Flask:
if config is None:
config = load_config(config_path)
current_app = Flask(__name__,
template_folder=..,
static_folder=..)
current_app.config.update(config)
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
db.init_app(current_app)
with current_app.app_context():
# ..
init_extensions(current_app)
# ..
return current_app
## .. other stuff ..
if __name__ == "__main__":
app = create_app()
app.run()
init_extensions
并且
def init_extensions(app: Flask) -> None:
"""
Initialize Flask extensions.
:param app: Flask application instance
"""
# other inits ..
# init OAuth
init_oauth(app)
是:
init_oauth
这里棘手的问题是我想添加一个新函数,例如
from authlib.integrations.flask_client import OAuth
from flask import Flask
oauth = OAuth()
def init_oauth(app: Flask) -> None:
oauth.init_app(app)
oauth.register(
name='google',
client_id=app.config['GOOGLE_OAUTH_CLIENT_ID'],
client_secret=app.config['GOOGLE_OAUTH_CLIENT_SECRET'],
server_metadata_url='https://accounts.google.com/.well-known/openid-configuration',
client_kwargs={
'scope': 'openid email profile'
}
)
:
check_accessibility
这将允许我可以即时检查并打开/关闭登录选项,而不需要为用户尝试登录并发现服务器不工作或其他什么增加额外的麻烦。
oauth = OAuth()
def init_oauth(app: Flask) -> None:
# same as above
def check_accessibility() -> bool:
# True, if everything is ok;
# False - if >0 creds are incorrect OR
# 3rd party server is inaccessible OR
# whatever else ..
是否有任何简单的方法来实现此功能?如果没有,如何实现?
?
Check server accessibility -> Check creds (how)? -> Return bool
?
当然,可以添加一个函数来检查 OAuth 提供程序的可用性和凭据的有效性。以下是如何执行此操作的方法:
import requests
from authlib.integrations.flask_client import OAuth
from flask import Flask, current_app
oauth = OAuth()
def init_oauth(app: Flask) -> None:
oauth.init_app(app)
oauth.register(
name='google',
client_id=app.config['GOOGLE_OAUTH_CLIENT_ID'],
client_secret=app.config['GOOGLE_OAUTH_CLIENT_SECRET'],
server_metadata_url='https://accounts.google.com/.well-known/openid-configuration',
client_kwargs={
'scope': 'openid email profile'
}
)
def check_oauth_accessibility(provider_name: str = 'google') -> bool:
"""
检查 OAuth 提供程序的可访问性和凭据的有效性。
Args:
provider_name: OAuth 提供程序的名称(例如,'google')。
Returns:
如果提供程序可访问且凭据有效,则为 True,否则为 False。
"""
try:
provider = oauth.create_client(provider_name)
# 获取服务器元数据以验证连接和凭据。
response = requests.get(provider.load_server_metadata_url())
response.raise_for_status() # 如果状态码不是 200,则引发异常
return True
except requests.exceptions.RequestException as e:
current_app.logger.error(f"无法访问或验证 {provider_name} OAuth 提供程序: {e}")
return False
except Exception as e:
current_app.logger.error(f"检查 {provider_name} OAuth 提供程序时出错: {e}")
return False
说明:
-
check_oauth_accessibility
函数: -
接收
provider_name
作为参数,允许检查不同的提供程序。 -
使用
oauth.create_client
创建一个 OAuth 客户端实例。 -
使用
requests.get
获取提供程序的服务器元数据。 -
response.raise_for_status()
检查请求是否成功(状态码 200)。如果请求不成功,则引发异常,导致函数返回False
。 -
如果没有异常,则表示提供程序可访问且凭据有效,函数返回
True
。 -
错误处理:
-
使用
try...except
块捕获requests.exceptions.RequestException
和其他可能发生的异常。 -
使用
current_app.logger.error
记录发生的任何错误,以便于调试。
如何使用:
可以在应用程序启动时或需要时调用
check_oauth_accessibility
函数:
@app.route('/login')
def login():
if not check_oauth_accessibility():
flash('OAuth 登录当前不可用。请稍后再试。', 'error')
return redirect(url_for('index'))
# ... 继续 OAuth 登录流程 ...
其他注意事项:
- 可能希望实现一个缓存机制,以避免每次都检查 OAuth 提供程序的可访问性。
- 考虑为不同的错误情况提供更具体的错误消息,例如凭据无效或服务器不可访问。
- 确保在生产环境中妥善处理错误,例如将用户重定向到错误页面或提供其他登录选项。