Ember Simple Auth в Firefox: аутентификация выдает ошибку

Я расширяю базовый класс аутентификации Ember Simple Auth, чтобы разрешить аутентификацию с помощью Google. Пока он работает на Safari 8 и Chrome 41 (оба на Yosemite) без ошибок. Однако в Firefox 35 выдается ошибка, которой нет в других браузерах. Вот мой класс аутентификатора Google:

App.GoogleAuthenticator = SimpleAuth.Authenticators.Base.extend({
    // constants for Google API
    GAPI_CLIENT_ID: 'the client id',
    GAPI_SCOPE: ['email'],
    GAPI_TOKEN_VERIFICATION_ENDPOINT: 'https://www.googleapis.com/oauth2/v2/tokeninfo',

    // method for scheduleing a single token refresh
    // time in milliseconds
    scheduleSingleTokenRefresh: function(time) {
        var self = this;
        return new Ember.RSVP.Promise(function(resolve, reject) {
            Ember.run.later(self, function() {
                gapi.auth.authorize({
                    client_id: self.GAPI_CLIENT_ID,
                    scope: self.GAPI_SCOPE,
                    immediate: true
                }, function(data) {
                    if (data && !data.error) {
                        resolve(data);
                    } else {
                        reject((data || {}).error);
                    }
                });
            }, time);
        });
    },
    // WIP: recursive method that reschedules another token refresh after the previous scheduled one was fulfilled
    // usage: scheduleTokenRefreshes(time until token should refresh for the first time, time between subsequent refreshes)
    // usage: scheduleTokenRefreshes(time between refreshes)
    scheduleTokenRefreshes: function(time1, time2) {
        var self = this;
        // if there is a time2, schedule a single refresh, wait for it to be fulfilled, then call myself to schedule again
        if (!Ember.isEmpty(time2)) {
            self.scheduleSingleTokenRefresh(time1)
            .then(function() {
                self.scheduleTokenRefreshes(time2);
            });
        // if there isn't a time2, simply schedule a single refresh, then call myself to schedule again
        } else {
            self.scheduleSingleTokenRefresh(time1)
            .then(function() {
                self.scheduleTokenRefreshes(time1);
            });
        }
    },

    // method that restores the session on reload
    restore: function(data) {
        var self = this;
        return new Ember.RSVP.Promise(function(resolve, reject) {
            console.log(data);
            if (Ember.isEmpty(data.access_token)) {
                reject();
                return;
            }
            // schedule a refresh 15 minutes before it expires or immediately if it expires in < 15
            var timeNow = Math.floor(Date.now() / 1000);
            var expiresAt = +data.expires_at;
            var timeDifference = expiresAt - timeNow;
            var schedulingDelay = Math.floor(timeDifference - 15 * 60);
            schedulingDelay = schedulingDelay < 0 ? 0 : schedulingDelay;
            self.scheduleTokenRefreshes(schedulingDelay * 1000, 45 * 60);
            resolve(data);
        });
    },
    // method that authenticates
    authenticate: function() {
        var self = this;
        return new Ember.RSVP.Promise(function(resolve, reject) {
            gapi.auth.authorize({
                client_id: self.GAPI_CLIENT_ID,
                scope: self.GAPI_SCOPE
            }, function(data) {
                if (data && !data.error) {
                    // schedule a refresh in 45 minutes
                    var schedulingDelay = 45 * 60;
                    self.scheduleTokenRefreshes(schedulingDelay * 1000);
                    resolve(data);
                } else {
                    reject((data || {}).error);
                }
            });
        });
    },
    // method that logs the user out and revokes the token
    invalidate: function(data) {
        var self = this;
        return new Ember.RSVP.Promise(function(resolve, reject) {
            // send a GET request to revoke the token
            Ember.$.ajax({
                type: 'GET',
                url: 'https://accounts.google.com/o/oauth2/revoke?token=' + self.get('session.access_token'),
                contentType: 'application/json',
                dataType: 'jsonp'
            })
            .done(function(successData) {
                resolve(successData);
            })
            .fail(function(error) {
                reject(error);
            });
        });
    }
});

Когда всплывающее окно закрывается после успешного входа в систему со стороны Google, в консоли Firefox появляется эта ошибка:

Error: Assertion Failed: Error: Permission denied to access property 'toJSON' ember.js:13749
"__exports__.default<.persist@http://127.0.0.1/~jonchan/test/bower_components/ember-simple-auth/simple-auth.js:1524:1
__exports__.default<.updateStore@http://127.0.0.1/~jonchan/test/bower_components/ember-simple-auth/simple-auth.js:1195:11
__exports__.default<.setup@http://127.0.0.1/~jonchan/test/bower_components/ember-simple-auth/simple-auth.js:1149:9
__exports__.default<.authenticate/</<@http://127.0.0.1/~jonchan/test/bower_components/ember-simple-auth/simple-auth.js:1066:13
tryCatch@http://127.0.0.1/~jonchan/test/bower_components/ember/ember.js:47982:16
invokeCallback@http://127.0.0.1/~jonchan/test/bower_components/ember/ember.js:47994:17
publish@http://127.0.0.1/~jonchan/test/bower_components/ember/ember.js:47965:11
@http://127.0.0.1/~jonchan/test/bower_components/ember/ember.js:29462:9
Queue.prototype.invoke@http://127.0.0.1/~jonchan/test/bower_components/ember/ember.js:848:11
Queue.prototype.flush@http://127.0.0.1/~jonchan/test/bower_components/ember/ember.js:913:13
DeferredActionQueues.prototype.flush@http://127.0.0.1/~jonchan/test/bower_components/ember/ember.js:718:13
Backburner.prototype.end@http://127.0.0.1/~jonchan/test/bower_components/ember/ember.js:143:11
createAutorun/backburner._autorun<@http://127.0.0.1/~jonchan/test/bower_components/ember/ember.js:546:9
" ember.js:29488

Вот информация о версии:

DEBUG: Ember             : 1.9.1
DEBUG: Ember Data        : 1.0.0-beta.14.1
DEBUG: Handlebars        : 2.0.0
DEBUG: jQuery            : 2.1.3
DEBUG: Ember Simple Auth : 0.7.2

Больше всего смущает то, что это появляется только в Firefox. Это ошибка в Ember Simple Auth или Ember? Как это исправить?


person Jonathan Chan    schedule 30.01.2015    source источник


Ответы (2)


Я не знаю только о том, что Firefox выдает ошибку (у меня была аналогичная ошибка с Chrome 40), но есть ошибка в ember-simple-auth 0.7.2 с Ember 1.9, которая запрещает отправку фактического ответа об ошибке в authenticate метод в аутентификаторе.

Если вы вернете reject() в функции отклонения authenticate, это не вызовет дополнительной ошибки. Однако это не будет распространять статус ошибки или сообщение, поэтому я считаю это ошибкой.

На github был предложен обходной путь по этой проблеме путем временной установки Ember.onerror=Ember.K, чтобы не распространялись дополнительные ошибки, хотя он будет распространять исходный отказ authenticate со статусом ошибки.

Проблема в репозитории github упоминает только проблемы с тестированием this, но у меня была эта проблема в обычном коде.

см.: https://github.com/simplabs/ember-simple-auth/issues/407

person Density 21.5    schedule 30.01.2015
comment
Спасибо за информацию, но возврат reject() не решает проблему. Похоже, это другая проблема. По какой-то причине примеры в Ember Simple Auth эта ошибка не возникает. На данный момент я пытаюсь изменить свой код, чтобы он больше походил на пример, и выяснить, что не так. - person Jonathan Chan; 31.01.2015
comment
Похоже, что эта проблема устранена в Ember 1.10, конкретно в 5-м пункте. Надеюсь, это касается того, с чем вы имеете дело. - person Jonathan Chan; 31.01.2015

Оказывается, ошибка была в части resolve метода authenticate. Вот что это исправило:

App.GoogleAuthenticator = SimpleAuth.Authenticators.Base.extend({
    authenticate: function() {
        return new Ember.RSVP.Promise(function(resolve, reject) {
            gapi.auth.authorize({
                client_id: 'the client id',
                scope: ['the scopes'],
            }, function(data) {
                if (data && !data.error) {
                    resolve({
                        access_token: data.access_token // !! passing the entire 'data' object caused the error somehow
                    });
                } else {
                    reject((data || {}).error);
                }
            });
        });
    },
    // ...
});

Я до сих пор не совсем уверен, почему это вызвало ошибку. Возможно, ответ API Google (полностью) каким-то образом несовместим с Ember Simple Auth.

person Jonathan Chan    schedule 31.01.2015