Flask:如何为所有方法注册一个包装器
Flask: how to register a wrapper to all methods
我一直在从瓶子换到烧瓶。如果我需要的代码不超过 20 行,我是那种更喜欢自己编写代码而不是从 Internet 下载程序包的人。以支持 Basic
身份验证协议为例。在瓶子里我可以写:
def allow_anonymous():
"""assign a _allow_anonymous flag to functions not requiring authentication"""
def wrapper(fn):
fn._allow_anonymous = True
return fn
return wrapper
def auth_middleware(fn):
"""perform authentication (pre-req)"""
def wrapper(*a, **ka):
# if the allow_anonymous annotation is set then bypass this auth
if hasattr(fn, '_allow_anonymous') and fn._allow_anonymous:
return fn(*a, **ka)
user, password = request.auth or (None, None)
if user is None or not check(user, password):
err = HTTPError(401, text)
err.add_header('WWW-Authenticate', 'Basic realm="%s"' % realm)
return err
return fn(*a, **ka)
return wrapper
...
app = Bottle()
app.install(middleware.auth_middleware)
以上代码为所有方法提供了对基本身份验证协议的完全支持,除非用 @allow_anonymous
包装器明确修饰。我只是烧瓶的初学者。我很难在不添加对更多 python 包或过多样板的依赖的情况下在烧瓶中完成上面的瓶兼容代码。 flask 中是如何直接清楚地处理的?
如果你愿意,你绝对可以自己使用 flask-httpauth 的一些功能:-P
我想你需要玩一些 before_request
游戏(不是很漂亮),或者用每个 api 端点的修饰方法调用 flask 的 add_url_rule
(或者有您自己的 route
装饰器将执行此操作)。 add_url_rule
获取一个视图函数,它通常是您的 api 端点处理程序,但在您的情况下,将是一个包装方法,其方式与您在 post 中提供的方法非常相似( auth_middleware
).
要点:
from flask import Flask, make_response, request
app = Flask(__name__)
def view_wrapper(fn):
"""
Create a wrapped view function that checks user authorization
"""
def protected_view(*a, **ka):
# if the allow_anonymous annotation is set then bypass this auth
if hasattr(fn, '_allow_anonymous') and fn._allow_anonymous:
return fn(*a, **ka)
# consult werkzeug's authorization mixin
user, password = (request.authorization.username, request.authorization.password) if request.authorization else (None, None)
if user is None or not check(user, password):
err_response = make_response(text, 401)
err_response.headers['WWW-Authenticate'] = 'Basic realm="%s"' % realm
return err_response
return fn(*a, **ka)
return protected_view
# An endpoint
def hello():
return 'hello there'
app.add_url_rule('/', 'hello', view_wrapper(hello))
当然,这可以(并且应该)通过 Blueprints 等进一步增强
注意 #1:这是从 SO 中的单独答案中抄袭的。
注意#2:这不使用蓝图。同样,我是 Flask 的新手,我很欣赏蓝图将有助于应用程序扩展,但一次一步......
def allow_anonymous(decorated_function):
decorated_function.is_public = True
return decorated_function
@app.before_request
def auth_middleware():
fn = app.view_functions[request.endpoint]
if hasattr(fn, 'allow_anonymous') and fn.allow_anonymous:
# anonymous permitted
return
elif my_custom_authentication():
# anonymous not permitted authentication succeeded
return
else:
# anonymous not permitted authentication failed
err_response = make_response(text, 401)
err_response.headers['WWW-Authenticate'] = 'Basic realm="%s"' % realm
return err_response
@app.route('/public_thing')
@allow_anonymous
def public_thing():
return 'yo'
@app.route('/regular_thing')
def regular_thing():
return 'if you can read this youre authenticated.'
我一直在从瓶子换到烧瓶。如果我需要的代码不超过 20 行,我是那种更喜欢自己编写代码而不是从 Internet 下载程序包的人。以支持 Basic
身份验证协议为例。在瓶子里我可以写:
def allow_anonymous():
"""assign a _allow_anonymous flag to functions not requiring authentication"""
def wrapper(fn):
fn._allow_anonymous = True
return fn
return wrapper
def auth_middleware(fn):
"""perform authentication (pre-req)"""
def wrapper(*a, **ka):
# if the allow_anonymous annotation is set then bypass this auth
if hasattr(fn, '_allow_anonymous') and fn._allow_anonymous:
return fn(*a, **ka)
user, password = request.auth or (None, None)
if user is None or not check(user, password):
err = HTTPError(401, text)
err.add_header('WWW-Authenticate', 'Basic realm="%s"' % realm)
return err
return fn(*a, **ka)
return wrapper
...
app = Bottle()
app.install(middleware.auth_middleware)
以上代码为所有方法提供了对基本身份验证协议的完全支持,除非用 @allow_anonymous
包装器明确修饰。我只是烧瓶的初学者。我很难在不添加对更多 python 包或过多样板的依赖的情况下在烧瓶中完成上面的瓶兼容代码。 flask 中是如何直接清楚地处理的?
如果你愿意,你绝对可以自己使用 flask-httpauth 的一些功能:-P
我想你需要玩一些 before_request
游戏(不是很漂亮),或者用每个 api 端点的修饰方法调用 flask 的 add_url_rule
(或者有您自己的 route
装饰器将执行此操作)。 add_url_rule
获取一个视图函数,它通常是您的 api 端点处理程序,但在您的情况下,将是一个包装方法,其方式与您在 post 中提供的方法非常相似( auth_middleware
).
要点:
from flask import Flask, make_response, request
app = Flask(__name__)
def view_wrapper(fn):
"""
Create a wrapped view function that checks user authorization
"""
def protected_view(*a, **ka):
# if the allow_anonymous annotation is set then bypass this auth
if hasattr(fn, '_allow_anonymous') and fn._allow_anonymous:
return fn(*a, **ka)
# consult werkzeug's authorization mixin
user, password = (request.authorization.username, request.authorization.password) if request.authorization else (None, None)
if user is None or not check(user, password):
err_response = make_response(text, 401)
err_response.headers['WWW-Authenticate'] = 'Basic realm="%s"' % realm
return err_response
return fn(*a, **ka)
return protected_view
# An endpoint
def hello():
return 'hello there'
app.add_url_rule('/', 'hello', view_wrapper(hello))
当然,这可以(并且应该)通过 Blueprints 等进一步增强
注意 #1:这是从 SO 中的单独答案中抄袭的。
注意#2:这不使用蓝图。同样,我是 Flask 的新手,我很欣赏蓝图将有助于应用程序扩展,但一次一步......
def allow_anonymous(decorated_function):
decorated_function.is_public = True
return decorated_function
@app.before_request
def auth_middleware():
fn = app.view_functions[request.endpoint]
if hasattr(fn, 'allow_anonymous') and fn.allow_anonymous:
# anonymous permitted
return
elif my_custom_authentication():
# anonymous not permitted authentication succeeded
return
else:
# anonymous not permitted authentication failed
err_response = make_response(text, 401)
err_response.headers['WWW-Authenticate'] = 'Basic realm="%s"' % realm
return err_response
@app.route('/public_thing')
@allow_anonymous
def public_thing():
return 'yo'
@app.route('/regular_thing')
def regular_thing():
return 'if you can read this youre authenticated.'