如何使用http协议实现社交账号认证
How to implement social account authentication using http protocol
我正在尝试使用 Flask、Google App Engine 和 Flask-dance 在本地实现 Google 社交登录。
我从这个 link.
中遵循了 Flask-dance 作者提供的示例
这是主文件:
from flask import Flask, url_for, redirect
from flask_dance.contrib.google import make_google_blueprint, google
from flask_dance.consumer import oauth_authorized, oauth_error
from werkzeug.contrib.fixers import ProxyFix
app = Flask('application')
app.wsgi_app = ProxyFix(app.wsgi_app)
# You must configure these 3 values from Google APIs console
# https://code.google.com/apis/console
GOOGLE_CLIENT_ID = 'my-client-id'
GOOGLE_CLIENT_SECRET = 'my-client-secret'
app.config["GOOGLE_OAUTH_CLIENT_ID"] = GOOGLE_CLIENT_ID
app.config["GOOGLE_OAUTH_CLIENT_SECRET"] = GOOGLE_CLIENT_SECRET
google_bp = make_google_blueprint(
client_id=app.config['GOOGLE_OAUTH_CLIENT_ID'],
client_secret=app.config['GOOGLE_OAUTH_CLIENT_SECRET'],
redirect_to="index_man_2",
scope=["https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email"]
)
app.register_blueprint(google_bp, url_prefix="/login")
@app.route("/login-gmail")
def index_gmail():
if not google.authorized:
return redirect(url_for("google.login"))
resp = google.get("/oauth2/v1/userinfo")
assert resp.ok, resp.text
return "ok"
当我访问 http://localhost:8080/login-gmail 时,服务器将我重定向到选择 google 帐户页面。然后,当我选择一个帐户时,出现此错误:
INFO 2019-07-11 14:47:13,476 module.py:861] default: "GET
/login/google HTTP/1.1" 302 989 WARNING 2019-07-11 14:47:21,345
urlfetch_stub.py:575] Stripped prohibited headers from URLFetch
request: ['Content-Length'] WARNING 2019-07-11 13:47:21,828
connectionpool.py:403] Failed to parse headers
(url=https://accounts.google.com:443/o/oauth2/token): expected
httplib.Message, got . Traceback (most recent call
last): File
"C:\Users\tah\Documents\some-name\m\src\lib\urllib3\connectionpool.py",
line 399, in _make_request
assert_header_parsing(httplib_response.msg) File "C:\Users\Tah\Documents\some-name\m\src\lib\urllib3\util\response.py",
line 56, in assert_header_parsing
type(headers))) TypeError: expected httplib.Message, got . error message : EXCEPTION IN (1982, ('Connection broken:
IncompleteRead(35 bytes read)', IncompleteRead(35 bytes read)))
('Connection broken: IncompleteRead(35 bytes read)', IncompleteRead(35
bytes read)) INFO 2019-07-11 13:47:21,884 recording.py:676] Saved;
key: appstats:041000, part: 455 bytes, full: 18063 bytes,
overhead: 0.000 + 0.012; link:
http://localhost:8080/_ah/stats/details?time=1562852841009 INFO
2019-07-11 14:47:21,895 module.py:861] default: "GET
/login/google/authorized?state=sfUHmqfKiy61fnvh1UUsVydJv3vO5L&code=4%2FgwHWN8roL2HIxqxtBoFKySXod_jErJ0NB7ofNpdFtLwS2Zebc2rx959sPDOvUThrdlKfQEKWAj0bEbtJxBsskao&scope=email+profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+openid&authuser=2&session_state=7ea8a7963e2773849220b0eb3ddf063f9c5e3ef8..3331&prompt=consent
HTTP/1.1" 500 41241
根据 this answer,我了解到如果 Flask-Dance 使用 HTTP 生成重定向 URL,这意味着 Flask 认为传入请求正在使用 HTTP。如果传入的请求实际上使用的是 HTTPS,那么 Flask 就会在某处感到困惑,主要是由于代理。但是这个答案并没有告诉我们如何修复错误。
感谢您的回答。
werkzeug library that Flask depends on recently updated to version 0.15. There were several backwards-incompatible changes in version 0.15, including changes to the ProxyFix 中间件。从您发布的代码示例来看,您似乎正在以适用于 werkzeug 0.14 的方式导入和使用它,但您需要为 0.15 进行一些更改。以下是您应该做的:
from werkzeug.middleware.proxy_fix import ProxyFix
app = Flask('application')
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1)
我假设你已经在 app.yaml:
中定义了这个环境变量
env_variables:
OAUTH_INSECURE_TRANSPORT: '1'
OAUTHLIB_INSECURE_TRANSPORT: '1'
要解决您的问题,您需要使用 requests toolbelt。 toolbelt 附带了几个不同的传输适配器供您处理请求。
首先,您需要安装库:
pip install -t lib requests-toolbelt
然后您需要将此行添加到主文件中:
import requests_toolbelt.adapters.appengine
# Use the App Engine Requests adapter. This makes sure that Requests uses
# URLFetch.
requests_toolbelt.adapters.appengine.monkeypatch()
因此,主文件将类似于:
from flask import Flask, url_for, redirect
from flask_dance.contrib.google import make_google_blueprint, google
from flask_dance.consumer import oauth_authorized, oauth_error
import requests_toolbelt.adapters.appengine
app = Flask('application')
# Use the App Engine Requests adapter. This makes sure that Requests uses
# URLFetch.
requests_toolbelt.adapters.appengine.monkeypatch()
# You must configure these 3 values from Google APIs console
# https://code.google.com/apis/console
GOOGLE_CLIENT_ID = 'my-client-id'
GOOGLE_CLIENT_SECRET = 'my-client-secret'
#...
我正在尝试使用 Flask、Google App Engine 和 Flask-dance 在本地实现 Google 社交登录。
我从这个 link.
中遵循了 Flask-dance 作者提供的示例这是主文件:
from flask import Flask, url_for, redirect
from flask_dance.contrib.google import make_google_blueprint, google
from flask_dance.consumer import oauth_authorized, oauth_error
from werkzeug.contrib.fixers import ProxyFix
app = Flask('application')
app.wsgi_app = ProxyFix(app.wsgi_app)
# You must configure these 3 values from Google APIs console
# https://code.google.com/apis/console
GOOGLE_CLIENT_ID = 'my-client-id'
GOOGLE_CLIENT_SECRET = 'my-client-secret'
app.config["GOOGLE_OAUTH_CLIENT_ID"] = GOOGLE_CLIENT_ID
app.config["GOOGLE_OAUTH_CLIENT_SECRET"] = GOOGLE_CLIENT_SECRET
google_bp = make_google_blueprint(
client_id=app.config['GOOGLE_OAUTH_CLIENT_ID'],
client_secret=app.config['GOOGLE_OAUTH_CLIENT_SECRET'],
redirect_to="index_man_2",
scope=["https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email"]
)
app.register_blueprint(google_bp, url_prefix="/login")
@app.route("/login-gmail")
def index_gmail():
if not google.authorized:
return redirect(url_for("google.login"))
resp = google.get("/oauth2/v1/userinfo")
assert resp.ok, resp.text
return "ok"
当我访问 http://localhost:8080/login-gmail 时,服务器将我重定向到选择 google 帐户页面。然后,当我选择一个帐户时,出现此错误:
INFO 2019-07-11 14:47:13,476 module.py:861] default: "GET /login/google HTTP/1.1" 302 989 WARNING 2019-07-11 14:47:21,345 urlfetch_stub.py:575] Stripped prohibited headers from URLFetch request: ['Content-Length'] WARNING 2019-07-11 13:47:21,828 connectionpool.py:403] Failed to parse headers (url=https://accounts.google.com:443/o/oauth2/token): expected httplib.Message, got . Traceback (most recent call last): File "C:\Users\tah\Documents\some-name\m\src\lib\urllib3\connectionpool.py", line 399, in _make_request assert_header_parsing(httplib_response.msg) File "C:\Users\Tah\Documents\some-name\m\src\lib\urllib3\util\response.py", line 56, in assert_header_parsing type(headers))) TypeError: expected httplib.Message, got . error message : EXCEPTION IN (1982, ('Connection broken: IncompleteRead(35 bytes read)', IncompleteRead(35 bytes read))) ('Connection broken: IncompleteRead(35 bytes read)', IncompleteRead(35 bytes read)) INFO 2019-07-11 13:47:21,884 recording.py:676] Saved; key: appstats:041000, part: 455 bytes, full: 18063 bytes, overhead: 0.000 + 0.012; link: http://localhost:8080/_ah/stats/details?time=1562852841009 INFO
2019-07-11 14:47:21,895 module.py:861] default: "GET /login/google/authorized?state=sfUHmqfKiy61fnvh1UUsVydJv3vO5L&code=4%2FgwHWN8roL2HIxqxtBoFKySXod_jErJ0NB7ofNpdFtLwS2Zebc2rx959sPDOvUThrdlKfQEKWAj0bEbtJxBsskao&scope=email+profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+openid&authuser=2&session_state=7ea8a7963e2773849220b0eb3ddf063f9c5e3ef8..3331&prompt=consent HTTP/1.1" 500 41241
根据 this answer,我了解到如果 Flask-Dance 使用 HTTP 生成重定向 URL,这意味着 Flask 认为传入请求正在使用 HTTP。如果传入的请求实际上使用的是 HTTPS,那么 Flask 就会在某处感到困惑,主要是由于代理。但是这个答案并没有告诉我们如何修复错误。
感谢您的回答。
werkzeug library that Flask depends on recently updated to version 0.15. There were several backwards-incompatible changes in version 0.15, including changes to the ProxyFix 中间件。从您发布的代码示例来看,您似乎正在以适用于 werkzeug 0.14 的方式导入和使用它,但您需要为 0.15 进行一些更改。以下是您应该做的:
from werkzeug.middleware.proxy_fix import ProxyFix
app = Flask('application')
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1)
我假设你已经在 app.yaml:
中定义了这个环境变量env_variables:
OAUTH_INSECURE_TRANSPORT: '1'
OAUTHLIB_INSECURE_TRANSPORT: '1'
要解决您的问题,您需要使用 requests toolbelt。 toolbelt 附带了几个不同的传输适配器供您处理请求。
首先,您需要安装库:
pip install -t lib requests-toolbelt
然后您需要将此行添加到主文件中:
import requests_toolbelt.adapters.appengine
# Use the App Engine Requests adapter. This makes sure that Requests uses
# URLFetch.
requests_toolbelt.adapters.appengine.monkeypatch()
因此,主文件将类似于:
from flask import Flask, url_for, redirect
from flask_dance.contrib.google import make_google_blueprint, google
from flask_dance.consumer import oauth_authorized, oauth_error
import requests_toolbelt.adapters.appengine
app = Flask('application')
# Use the App Engine Requests adapter. This makes sure that Requests uses
# URLFetch.
requests_toolbelt.adapters.appengine.monkeypatch()
# You must configure these 3 values from Google APIs console
# https://code.google.com/apis/console
GOOGLE_CLIENT_ID = 'my-client-id'
GOOGLE_CLIENT_SECRET = 'my-client-secret'
#...