Вход в Google с Passportjs не проходит проверку подлинности
Я использую паруса с паспортом для аутентификации. Я использую passport-google-oauth(OAuth2Strategy) и passport-facebook для включения входа в Google.
Я не слишком хорошо разбираюсь в Passport, так что извините, если это вопрос новичка. Я настроил вход через Facebook, и он работает просто отлично. В Google я получаю код авторизации после разрешения доступа к приложению, но в итоге я не прошел проверку подлинности. Я предполагаю, что один и тот же код должен работать как для Facebook, так и для Google, так как обе стратегии основаны на oauth2.
Я даже не уверен, каким кодом поделиться, так как я использую автоматически сгенерированный код из sails-generate-auth, но не знаю, могу ли я поделиться чем-то еще.
Любые идеи о том, почему это может происходить? Приложение размещается локально, но это вряд ли будет проблемой, так как я все равно добираюсь до стадии авторизации.
2 ответа
Хорошо, так что в конечном итоге это была известная проблема с API.
TL; DR: включить API Google+ и API контактов, как упомянуто здесь. (API контактов не требуется, как @AlexisN-o указал в комментариях. Моя установка работала как надо с отключенным API контактов. Это, очевидно, зависит от того, какую область вы используете.)
Я полагаю, что это не очень хороший способ потерпеть неудачу, так как это была ошибка API, которая была предотвращена. Во всяком случае, я копался в passport.authenticate
выяснить, что пошло не так. Это в конечном итоге называет authenticate
метод, определенный в пакете, соответствующем стратегии (в данном случае oauth2). Здесь (passport-google-oauth/lib/passport-google-oauth/oauth2.js
) Я обнаружил, что accessToken
действительно был извлечен из Google, так что все должно работать. Это указывало на проблему с запросами к URL-адресам токенов. Так что я рискнул немного дальше в passport-oauth2/lib/strategy.js
и наконец удалось записать эту ошибку:
{ [InternalOAuthError: failed to fetch user profile]
name: 'InternalOAuthError',
message: 'failed to fetch user profile',
oauthError:
{ statusCode: 403,
data: '{
"error": {
"errors": [{
"domain": "usageLimits",
"reason": "accessNotConfigured",
"message": "Access Not Configured. The API (Google+ API) is not enabled for your project. Please use the Google Developers Console to update your configuration.",
"extendedHelp": "https://console.developers.google.com"
}],
"code": 403,
"message": "Access Not Configured. The API (Google+ API) is not enabled for your project. Please use the Google Developers Console to update your configuration."
}
}'
} }
Это был конец охоты на меня, и первый результат поиска ошибок привел к правильному ответу. Странно исправить, хотя.
Я столкнулся с той же проблемой, и он был расположен здесь в api / services / passport.js:
// If the profile object contains a list of emails, grab the first one and
// add it to the user.
if (profile.hasOwnProperty('emails')) {
user.email = profile.emails[0].value;
}
// If the profile object contains a username, add it to the user.
if (profile.hasOwnProperty('username')) {
user.username = profile.username;
}
// If neither an email or a username was available in the profile, we don't
// have a way of identifying the user in the future. Throw an error and let
// whoever's next in the line take care of it.
if (!user.username && !user.email) {
return next(new Error('Neither a username nor email was available'));
}
Служба Google не возвращала profile.username
собственность
Из-за этого пользователь не сохраняется в базе данных и не может быть аутентифицирован. Затем обратный вызов паспорта получает пустого пользователя, поэтому функция, обрабатывающая ошибки, запускается, и пользователь перенаправляется на страницу входа.
Это изменение позволяет использовать displayName
собственность как username
:
// If the profile object contains a list of emails, grab the first one and
// add it to the user.
if (profile.hasOwnProperty('emails')) {
user.email = profile.emails[0].value;
}
// If the profile object contains a username, add it to the user.
if (profile.hasOwnProperty('username')) {
user.username = profile.username;
}
/** Content not generated BEGIN */
// If the username property was empty and the profile object
// contains a property "displayName", add it to the user.
if (!user.username && profile.hasOwnProperty('displayName')) {
console.log(profile); // <= Use it to check the content given by Google about the user
user.username = profile.displayName;
}
/** Content not generated END */
// If neither an email or a username was available in the profile, we don't
// have a way of identifying the user in the future. Throw an error and let
// whoever's next in the line take care of it.
if (!user.username && !user.email) {
return next(new Error('Neither a username nor email was available'));
}
Вы также можете использовать profile.id
собственность, потому что profile.displayName
не обязательно уникален (то есть: две учетные записи Google могут иметь идентичные displayName
). Но это также верно для разных служб: учетная запись Twitter также может иметь то же имя пользователя, что и учетная запись Facebook. Если оба зарегистрируются в вашем приложении, у вас будет ошибка. Это проблема из кода, сгенерированного sails-generate-auth
и вы должны адаптировать его к поведению, которое вы хотите.
Я предложу PR, если это решение работает и для вас.