【问题标题】:How can I make this Flask App more DRY (connecting to many oauth APIs)?我怎样才能使这个 Flask 应用程序更干燥(连接到许多 oauth API)?
【发布时间】:2013-12-17 14:25:49
【问题描述】:

我正在使用 Flask-oauthlib 连接到多个 API(例如 Twitter、GitHub 等)。目前,我将这些服务中的每一项都作为单独的蓝图。在每个服务的视图文件中,都有相同的三个视图:loginauthorizedget_token。现在的代码不是很干,但我很难理解如何集中这些视图(从概念上讲)。

我怎样才能让这个更干燥?我想从概念上理解,而不是有人真正为我编写代码。

以下是一些可能会有所帮助的项目。这是应用程序结构:

- App
    - Services
        - FourSquare BP
        - GitHub BP
        - Twitter BP
        - ...
    - Other BPs

通用 API 视图可能会归入Services/api_views.py

这是一个 API 蓝图视图文件 (Twitter) 的示例。

twitter = Blueprint('twitter', __name__, url_prefix='/twitter')
bp = twitter

bp.api = TwitterAPI()
bp.oauth = bp.api.oauth_app

# Below here is the exact same for each file.

@bp.route('/')
@login_required
def login():
    if current_user.get(bp.name, None):
        return redirect(url_for('frontend.index'))
    return bp.oauth.authorize(callback=url_for('.authorized', _external=True))

@bp.route('/authorized')
@bp.oauth.authorized_handler
def authorized(resp):
    if resp is None:
        flash(u'You denied the request to sign in.')
        return redirect(url_for('frontend.index'))

    if bp.oauth_type == 'oauth2':
        resp['access_token'] = (resp['access_token'], '') 

    current_user[bp.name] = resp
    current_user.save()

    flash('You were signed in to %s' % bp.name.capitalize())
    return redirect(url_for('frontend.index'))

@bp.oauth.tokengetter
def get_token(token=None):
    if bp.oauth_type == 'oauth2':
        return current_user.get(bp.name, None)['access_token']
    return current_user.get(bp.name, None)['oauth_token']

我尝试将视图放在一个类中然后导入它们,但是在使用各种装饰器时遇到了问题(oauth 装饰器最麻烦)。

【问题讨论】:

    标签: python oauth flask dry


    【解决方案1】:

    我想出了一些似乎是解决上述问题的好方法。如果这实际上是一个好的解决方案,请告诉我。

    我决定使用 Flask 基于类的视图。这让我大部分时间都可以为上面的每个主要 API 函数创建一个类视图:

    class APILoginView(View):
        decorators = [login_required]
    
        def __init__(self, blueprint):
            self.blueprint = blueprint
    
        def dispatch_request(self):
            if current_user.get(self.blueprint.name, None):
                return redirect(url_for('frontend.index'))
            return self.blueprint.oauth.authorize(callback=url_for('.authorized', _external=True))
    
    class APIAuthorizedView(View):
        decorators = [login_required]
    
        def __init__(self, blueprint):
            self.blueprint = blueprint
    
        def dispatch_request(self, resp):
            if resp is None:
                flash(u'You denied the request to sign in.')
                return redirect(url_for('frontend.index'))
    
            if self.blueprint.api.oauth_type == 'oauth2':
                resp['access_token'] = (resp['access_token'], '') #need to make it a tuple for oauth2 requests
    
            current_user[self.blueprint.name] = resp
            current_user.save()
    
            flash('You were signed in to %s' % self.blueprint.name.capitalize())
            return redirect(url_for('frontend.index'))
    

    这是比较容易的部分。更棘手的事情是弄清楚如何推广 Flask-OAuthLib 库所需的 tokengetter。这是我最终得到的结果:

    class APIToken():
        def __init__(self, blueprint):
            self.blueprint = blueprint
    
        def get_token(self, token=None):
            if self.blueprint.api.oauth_type == 'oauth2':
                return current_user.get(self.blueprint.name, None)['access_token']
            return current_user.get(self.blueprint.name, None)['oauth_token']
    

    最后,创建一个函数来在蓝图上注册这些视图:

    def registerAPIViews(blueprint):
        login_view = APILoginView.as_view('login', blueprint=blueprint)
        auth_view = blueprint.oauth.authorized_handler(
                            APIAuthorizedView.as_view('authorized', blueprint=blueprint))
    
        blueprint.add_url_rule('/', view_func=login_view)
        blueprint.add_url_rule('/authorized', view_func=auth_view)
    
        apiToken = APIToken(blueprint)
        token_getter = blueprint.oauth.tokengetter(apiToken.get_token)
    
        return blueprint
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多