【问题标题】:oath2 - Authorization Code Grant with Flask (accessing bitbucket)?oauth2 - 使用 Flask 授予授权码(访问 bitbucket)?
【发布时间】:2017-03-27 16:35:36
【问题描述】:

我正在测试各种oath2 工作流,我最想链接的一个是Authorization Code Grant

如果我直接复制/粘贴网址,我可以成功获得令牌。

我的意思是request accesscopy paste given URlenter it in a browseraccept authorizationcopy paste back callback url -> 访问资源。就像在这个例子中一样:

from requests_oauthlib import OAuth2Session


class ClientSecrets:
    """
    The structure of this class follows Google convention for `client_secrets.json`:
    https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
    Bitbucket does not emit this structure so it must be manually constructed.
    """
    client_id = "myid"
    client_secret = "mysecret"
    auth_uri = "https://bitbucket.org/site/oauth2/authorize"
    token_uri = "https://bitbucket.org/site/oauth2/access_token"
    server_base_uri = "https://api.bitbucket.org/"


def main():
    c = ClientSecrets()
    # Fetch a request token
    bitbucket = OAuth2Session(c.client_id)
    # Redirect user to Bitbucket for authorization
    authorization_url = bitbucket.authorization_url(c.auth_uri)
    print('Please go here and authorize: {}'.format(authorization_url[0]))
    # Get the authorization verifier code from the callback url
    redirect_response = raw_input('Paste the full redirect URL here:')
    # Fetch the access token
    bitbucket.fetch_token(
      c.token_uri,
      authorization_response=redirect_response,
      username=c.client_id,
      password=c.client_secret)
    # Fetch a protected resource, i.e. user profile
    r = bitbucket.get(c.server_base_uri + '1.0/user')
    print(r.content)

虽然如果我尝试使用 Flask 来模仿试图访问 bitbucket 的实际 Web 应用程序,但它无法获得访问权限。

我的 Flask 应用实现示例如下所示:

from flask import Flask, redirect, request, session

from requests_oauthlib import OAuth2Session

app = Flask(__name__)

client_id = 'myid'
client_secret = 'mysecret'
authorization_base_url = 'https://bitbucket.org/site/oauth2/authorize'
token_url = 'https://bitbucket.org/site/oauth2/access_token'
redirect_uri = 'https://127.0.0.1:5000/callback'


@app.route('/login')
def login():
    oauth2 = OAuth2Session(client_id, redirect_uri=redirect_uri)
    authorization_url, state = oauth2.authorization_url(
        authorization_base_url,

    )
    # State is used to prevent CSRF, keep this for later.
    session['oauth_state'] = state
    return redirect(authorization_url)


@app.route("/callback")
def callback():
    bitbucket = OAuth2Session(client_id, state=session['oauth_state'])
    bitbucket.fetch_token(
        token_url,
        client_secret=client_secret,
        authorization_response=request.url)
    return bitbucket.get('some_resource_url').content

if __name__ == '__main__':
    # Certificate and key files.
    context = ('cert/server.crt', 'cert/server.key')
    app.run(debug=True, ssl_context=context)

如果我像示例中那样运行应用程序,则在尝试访问 URL 时出现此错误:https://127.0.0.1:5000/login

File "/home/oerp/python-programs/flask-app/bitiface/test.py", line 23, in login
    session['oauth_state'] = state
  File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/werkzeug/local.py", line 350, in __setitem__
    self._get_current_object()[key] = value
  File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/sessions.py", line 130, in _fail
    raise RuntimeError('The session is unavailable because no secret '
RuntimeError: The session is unavailable because no secret key was set.  Set the secret_key on the application to something unique and secret.

看起来这与oath_state 有关。如果我评论 oath_state 分配并尝试像以前一样运行应用程序。然后我得到这个错误:

Traceback (most recent call last):
  File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1994, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1985, in wsgi_app
    response = self.handle_exception(e)
  File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1540, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/oerp/python-programs/flask-app/bitiface/test.py", line 33, in callback
    authorization_response=request.url)
  File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/requests_oauthlib/oauth2_session.py", line 244, in fetch_token
    self._client.parse_request_body_response(r.text, scope=self.scope)
  File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/clients/base.py", line 409, in parse_request_body_response
    self.token = parse_token_response(body, scope=scope)
  File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 376, in parse_token_response
    validate_token_parameters(params)
  File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 383, in validate_token_parameters
    raise_from_error(params.get('error'), params)
  File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/errors.py", line 325, in raise_from_error
    raise cls(**kwargs)
InvalidClientIdError: (invalid_request) redirect_uri does not match

看起来如果我跳过oath_session,那么它实际上会在回调时启动新会话,redirect_uri 将不匹配或类似的东西。

有人知道可能是什么问题吗?

更新

我用secret_key 更新了Flask,所以关于没有secret_key 的错误消失了,但第二个错误仍然存​​在。此错误:InvalidClientIdError: (invalid_request) redirect_uri does not match 在这部分代码引发:

...
...
bitbucket.fetch_token(
    token_url,
    client_secret=client_secret,
    authorization_response=request.url)
...
...

我不知道这是否相关,但打印request.url,它给了我这个:https://127.0.0.1:5000/callback?state=[bunch_of_random_symbols]。所以第一部分https://127.0.0.1:5000/callback 与我在消费者上设置的回调URL 完全相同。在我看来,它实际上是匹配的。 `

附:提供完整的追溯。

【问题讨论】:

  • 1.首先,您需要设置一个会话 secret key 才能使用 Flask 会话。 2. 你能延长最后的回溯吗?哪一行代码导致了这个错误?
  • @SergeyShubin 查看更新的问题。我已经回答了你的问题。

标签: python flask oauth-2.0


【解决方案1】:

主要错误的原因是redirect_uri 参数存在于授权 URL 中,但未在访问令牌请求中传递。正如RFC 6749 描述的那样:

redirect_uri

如果“redirect_uri”参数包含在第 4.1.1 节所述的授权请求中,并且它们的值必须相同,则为必需。

所以你需要用redirect_uri初始化你的回调OAuth会话:

@app.route("/callback")
def callback():
    bitbucket = OAuth2Session(
        client_id, state=session['oauth_state'], redirect_uri=redirect_uri
    )

为什么我们需要发送redirect_uri 来获取访问令牌是开发人员中相当普遍的问题。 Security.Stackexchange 上的This discussion 可能会有所帮助。

至于第一个错误:

RuntimeError: The session is unavailable because no secret key was set.  Set the secret_key on the application to something unique and secret.

当您尝试在 Flask 会话中保存一些信息但未设置 Flask 应用程序的 secret key 时会引发此问题。

【讨论】:

    猜你喜欢
    • 2018-05-26
    • 1970-01-01
    • 2017-03-06
    • 1970-01-01
    • 2020-05-05
    • 2018-01-12
    • 2017-08-31
    • 2019-12-31
    • 2022-08-16
    相关资源
    最近更新 更多