【发布时间】:2020-10-02 08:13:32
【问题描述】:
我想向网站添加“通过 GMail 登录”功能。我创建login.html 和project.py 来处理响应。
我给login.html添加了一个按钮:
function renderButton() {
gapi.signin2.render('my-signin2', {
'scope': 'profile email',
'width': 240,
'height': 50,
'longtitle': true,
'theme': 'dark',
'onsuccess': signInCallback,
'onfailure': signInCallback
});
};
我有一个回调函数。在浏览器控制台中,我可以看到响应包含access_token、id_token(有什么区别?)和我的用户配置文件详细信息(姓名、电子邮件等),所以请求本身一定是成功的,但是,@调用 987654327@ 函数是因为我的 gconnect 处理程序返回的 response 是 401:
function signInCallback(authResult) {
var access_token = authResult['wc']['access_token'];
if (access_token) {
// Hide the sign-in button now that the user is authorized
$('#my-signin2').attr('style', 'display: none');
// Send the one-time-use code to the server, if the server responds, write a 'login successful' message to the web page and then redirect back to the main restaurants page
$.ajax({
type: 'POST',
url: '/gconnect?state={{STATE}}',
processData: false,
data: access_token,
contentType: 'application/octet-stream; charset=utf-8',
success: function(result)
{
....
},
error: function(result)
{
if (result)
{
// THIS CASE IS EXECUTED, although authResult['error'] is undefined
console.log('Logged in successfully as: ' + authResult['error']);
} else if (authResult['wc']['error'])
{
....
} else
{
....
}//else
}//error function
});//ajax
};//if access token
};//callback
处理对 Google 的 ajax 请求的代码在尝试获取 credentials = oauth_flow.step2_exchange(code) 时抛出 FlowExchangeError :
@app.route('/gconnect', methods=['POST'])
def gconnect():
if request.args.get('state') != login_session['state']:
response = make_response(json.dumps('Invalid state parameter.'), 401)
response.headers['Content-Type'] = 'application/json'
return response
# Obtain authorization code
code = request.data
try:
# Upgrade the authorization code into a credentials object
oauth_flow = flow_from_clientsecrets('client_secrets.json', scope='')
oauth_flow.redirect_uri = 'postmessage'
##### THROWS EXCEPTION HERE #####
credentials = oauth_flow.step2_exchange(code)
except FlowExchangeError:
response = make_response(
json.dumps('Failed to upgrade the authorization code.'), 401)
response.headers['Content-Type'] = 'application/json'
return response
# Check that the access token is valid.
access_token = credentials.access_token
url = ('https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=%s'
% access_token)
h = httplib2.Http()
result = json.loads(h.request(url, 'GET')[1])
# If there was an error in the access token info, abort.
if result.get('error') is not None:
response = make_response(json.dumps(result.get('error')), 500)
response.headers['Content-Type'] = 'application/json'
return response
# Verify that the access token is used for the intended user.
gplus_id = credentials.id_token['sub']
if result['user_id'] != gplus_id:
response = make_response(
json.dumps("Token's user ID doesn't match given user ID."), 401)
response.headers['Content-Type'] = 'application/json'
return response
# Verify that the access token is valid for this app.
if result['issued_to'] != CLIENT_ID:
response = make_response(
json.dumps("Token's client ID does not match app's."), 401)
print "Token's client ID does not match app's."
response.headers['Content-Type'] = 'application/json'
return response
stored_access_token = login_session.get('access_token')
stored_gplus_id = login_session.get('gplus_id')
if stored_access_token is not None and gplus_id == stored_gplus_id:
response = make_response(json.dumps('Current user is already connected.'),
200)
response.headers['Content-Type'] = 'application/json'
return response
# Store the access token in the session for later use.
login_session['access_token'] = credentials.access_token
login_session['gplus_id'] = gplus_id
# Get user info
userinfo_url = "https://www.googleapis.com/oauth2/v1/userinfo"
params = {'access_token': credentials.access_token, 'alt': 'json'}
answer = requests.get(userinfo_url, params=params)
data = answer.json()
login_session['username'] = data['name']
login_session['picture'] = data['picture']
login_session['email'] = data['email']
output = ''
output += '<h1>Welcome, '
output += login_session['username']
return output
我检查了我从 Google API 获得的 client_secrets.json,似乎没问题,我需要更新它吗?
{"web":{"client_id":"blah blah blah.apps.googleusercontent.com","project_id":"blah","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"blah client secret","redirect_uris":["http://localhost:1234"],"javascript_origins":["http://localhost:1234"]}}
为什么 credentials = oauth_flow.step2_exchange(code) 会失败?
这是我第一次实现这个,我正在学习 Web 和 OAuth,所有的概念都很难一次掌握。我也在使用 Udacity OAuth 课程,但他们的代码很旧并且不起作用。我可能在这里遗漏了什么?
【问题讨论】:
标签: python authentication flask oauth-2.0 google-oauth