Ich baue eine App auf Google App Engine mit Flask. Ich implementiere die Google+ Anmeldung über den serverseitigen Ablauf, der in https://developers.google.com/+/web/signin/server-side-flow beschrieben ist. Bevor ich zu App Engine wechselte, hatte ich einen sehr ähnlichen Ablauf. Vielleicht habe ich seitdem einen Fehler eingeführt. Oder vielleicht ist es ein Problem mit meiner Implementierung in App Engine.Google+ Anmeldung - Server Side Flow - Python - Google App Engine
Ich glaube, die URL, umgeleitet durch den Google-Login-Flow, sollte ein GET-Argument "gplus_id" haben, aber ich empfange diesen Parameter nicht.
Ich habe eine Login-Button erstellt von:
(function() {
var po = document.createElement('script');
po.type = 'text/javascript'; po.async = true;
po.src = 'https://plus.google.com/js/client:plusone.js?onload=render';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(po, s);
})();
function render() {
gapi.signin.render('gplusBtn', {
'callback': 'onSignInCallback',
'clientid': '{{ CLIENT_ID }}',
'cookiepolicy': 'single_host_origin',
'requestvisibleactions': 'http://schemas.google.com/AddActivity',
'scope': 'https://www.googleapis.com/auth/plus.login',
'accesstype': 'offline',
'width': 'iconOnly'
});
}
im JavaScript-Code für die Seite, die ich eine Funktion haben, um den Fluss zu initiieren:
var helper = (function() {
var authResult = undefined;
return {
onSignInCallback: function(authResult) {
if (authResult['access_token']) {
// The user is signed in
this.authResult = authResult;
helper.connectServer();
} else if (authResult['error']) {
// There was an error, which means the user is not signed in.
// As an example, you can troubleshoot by writing to the console:
console.log('GPlus: There was an error: ' + authResult['error']);
}
console.log('authResult', authResult);
},
connectServer: function() {
$.ajax({
type: 'POST',
url: window.location.protocol + '//' + window.location.host + '/connect?state={{ STATE }}',
contentType: 'application/octet-stream; charset=utf-8',
success: function(result) {
// After we load the Google+ API, send login data.
gapi.client.load('plus','v1',helper.otherLogin);
},
processData: false,
data: this.authResult.code,
error: function(e) {
console.log("connectServer: error: ", e);
}
});
}
}
})();
/**
* Calls the helper method that handles the authentication flow.
*
* @param {Object} authResult An Object which contains the access token and
* other authentication information.
*/
function onSignInCallback(authResult) {
helper.onSignInCallback(authResult);
}
Dieser den Fluss beginnt an „/ connect "(Siehe Schritt 8 in the above doc verwiesen):
@app.route('/connect', methods=['GET', 'POST'])
def connect():
# Ensure that this is no request forgery going on, and that the user
# sending us this connect request is the user that was supposed to.
if request.args.get('state', '') != session.get('state', ''):
response = make_response(json.dumps('Invalid state parameter.'), 401)
response.headers['Content-Type'] = 'application/json'
return response
# Normally the state would be a one-time use token, however in our
# simple case, we want a user to be able to connect and disconnect
# without reloading the page. Thus, for demonstration, we don't
# implement this best practice.
session.pop('state')
gplus_id = request.args.get('gplus_id')
code = request.data
try:
# Upgrade the authorization code into a credentials object
oauth_flow = client.flow_from_clientsecrets('client_secrets.json', scope='')
oauth_flow.redirect_uri = 'postmessage'
credentials = oauth_flow.step2_exchange(code)
except client.FlowExchangeError:
app.logger.debug("connect: Failed to upgrade the authorization code")
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.
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
...
jedoch die Strömung stoppt bei if result['user_id'] != gplus_id:
, und sagen, dass die Benutzer-ID des Tokens nicht mit der angegebenen Benutzer-ID übereinstimmt. result['user_id']
ist eine gültige Benutzer-ID, aber gplus_id
ist Keine.
Die Zeile gplus_id = request.args.get('gplus_id')
erwartet, dass die GET-Argumente 'gplus_id' enthalten, aber sie enthalten nur 'state'. Ist das ein Problem mit meiner javascript connectServer Funktion? Sollte ich "gplus_id" dort einschließen? Sicher weiß ich es zu diesem Zeitpunkt nicht. Oder etwas anderes?
am Nachmittag mit diesem Problem verloren. Ich habe die Lösung den Google-Entwicklern vorgelegt. Wenn Sie es auch tun können, würde vielleicht anderen helfen, nicht so viel Zeit zu verlieren. Vielen Dank! – marcelocra
Es gibt zu viele Lücken in der Dokumentation zu Google+ Sign-in und zur tatsächlichen Implementierung. – Shekhar