Вход в Google - выключение при обновлении

У меня есть следующая настройка:

.service('googleService', ['$q', function ($q) {
    var self = this;

    this.load = function(){
        var deferred = $q.defer();
        gapi.load('auth2', function(){
            var auth2 = gapi.auth2.init();
            auth2.then(function(){ deferred.resolve(); });
            addAuth2Functions(auth2);
        });
        return deferred.promise;
    };

    function addAuth2Functions(auth2) {

        self.isSignedIn = function(){
            return auth2.isSignedIn.get();
        }

        self.signOut = function(){
            var deferred = $q.defer();
            auth2.signOut().then(deferred.resolve, deferred.reject);
            return deferred.promise;
        };

        self.getProfile = function() {
            if(auth2.isSignedIn.get()) return { signed_in: true, access_token: auth2.currentUser.get().Zi.id_token,profile: auth2.currentUser.get().getBasicProfile() };
            else return { signed_in: false };
        }

    }

}])

.config(function($stateProvider, $urlRouterProvider, $locationProvider) {

    $locationProvider.html5Mode(true);
    $urlRouterProvider.otherwise('/cloud');

    var guest = ['$q', '$rootScope', '$stateParams', 'googleService', function ($q, $rootScope, $stateParams, googleService) { 

        var deferred = $q.defer(); 

        googleService.load().then(function(){ 
            $q.when(googleService.isSignedIn()).then(function(r){ 
                if(r) deferred.reject(); 
                else deferred.resolve(); 
            }) 
        }); 

        return deferred.promise; 
    }];

    var authenticated = ['$q', '$rootScope', '$stateParams', 'googleService', function ($q, $rootScope, $stateParams, googleService) { 

        var deferred = $q.defer(); 

        googleService.load().then(function(){ 
            $q.when(googleService.getProfile()).then(function(p) { 
                if(p.signed_in) { 
                    deferred.resolve(); 
                    localStorage['access_token'] = p.access_token;
                    $rootScope.profile = p.profile; 
                } else deferred.reject(); 
            }) 
        }); 

        return deferred.promise; 
    }];

    $stateProvider

    .state('login', {
        url: '/',
        views: { 'main': { templateUrl: 'pages/templates/login.html', controller: 'login' } },
        resolve: { authenticated: guest }
    })

    .state('cloud', {
        url: '/cloud',
        views: { 'main': { templateUrl: 'pages/templates/cloud.html', controller: 'cloud' } },
        resolve: { authenticated: authenticated }
    })

})

.controller('login', ['$rootScope', '$scope', '$q', '$state', 'googleService', function ($rootScope, $scope, $q, $state, googleService) {
    $scope.options = { 'onsuccess': function(response) { $state.go('cloud'); } }
}])

.controller('cloud', ['$rootScope', '$scope', '$timeout', '$http', '$httpParamSerializerJQLike', function ($rootScope, $scope, $timeout, $http, $httpParamSerializerJQLike) { 

}]);

В основном, что происходит, когда я вхожу в систему с помощью кнопки входа в Google, он подписывается, а googleService.getProfile() говорит, что я вошел.

Однако, если я обновляю страницу, googleService.isSignedIn() возвращает false.

Может ли кто-нибудь увидеть проблему, почему он будет возвращать false? Есть ли что-то еще, что мне нужно сделать, чтобы убедиться, что Google помнит меня?

Ответ 1

Основная проблема заключается в том, что вы вызываете gapi.auth2.init() снова и снова через googleService.load().

Мое предложение состоит в том, чтобы сохранить инициализацию promises для повторного использования, а не для ее создания много раз.

Вам также необходимо добавить условие для обработки токена с истекшим доступом.

.service('googleService', ['$q', function ($q) {
    const auth2InitPromise = $q(function(resolve) {
        gapi.load('auth2', function() {
            var auth2 = gapi.auth2.init();
            auth2.then(function() {
                resolve();
            });
        })
    });

    this.isSignedIn = function() {
        return auth2InitPromise.then(function() {
            return gapi.auth2.getAuthInstance().isSignedIn.get();
        });
    };

    this.signOut = function() {
        return auth2InitPromise.then(function() {
            const auth2 = gapi.auth2.getAuthInstance();
            return $q(function(resolve, reject) {
                auth2.signOut().then(resolve, reject);
            });
        });
    };

    this.getProfile = function() {
        return this.isSignedIn().then(function(isSignedIn) {
            if (isSignedIn) {
                const currentUser = gapi.auth2.getAuthInstance().currentUser.get();
                const authResponse = currentUser.getAuthResponse();
                return $q.when(authResponse.expires_at > Date.now() ? authResponse : currentUser.reloadAuthResponse()).then(function(ar) {
                    return {
                        signed_in: true,
                        access_token: ar.id_token,
                        profile: currentUser.getBasicProfile()
                    }                        
                });
            } else {
                return { signed_in: false };
            }
        });
    };

}])

Каждый из ваших методов обслуживания (isSignedIn, signOut и getProfile) теперь возвращает обещание, которое разрешается только после инициализации API auth2, однако это только когда-либо происходит один раз.


Например

var authenticated = ['$q', '$rootScope', '$window', 'googleService', function ($q, $rootScope, $window, googleService) {
    return googleService.getProfile().then(function(p) {
        if (p.signed_in) {
            $window.localStorage.setItem('access_token', p.access_token);
            $rootScope.profile = p.profile;
            return true; // resolvers should always resolve with something   
        } else {
            return $q.reject();
        }
    });
}];

Ответ 2

Вам нужно включить authenticated в качестве зависимости в вашем контроллере cloud. Кроме того, в вашем googleService в вашем обработчике успеха вы должны defer.resolve() после выполнить localStorage['access_token'] = p.access_token; и $rootScope.profile = p.profile;

Ответ 3

Привет Вносите следующие изменения в свой код и дайте мне знать, если он работает.

.service('googleService', ['$q', function ($q) {
    var self = this;

    this.load = function(){
        gapi.load('auth2', callback);            
    };

    function callback(){
        var deferred = $q.defer();
        gapi.auth2.init()//use your client credentials here
        .then(function(){ deferred.resolve(); });
        return deferred.promise;
    }


    self.isSignedIn=function (auth2){
        return auth2.isSignedIn.get();
    };

    self.signOut =function(auth2){
        var deferred = $q.defer();
        auth2.signOut().then(deferred.resolve, deferred.reject);
        return deferred.promise;
    };

    self.getProfile= function(auth2) {
        if(auth2.isSignedIn.get()) return { signed_in: true, access_token: auth2.currentUser.get().Zi.id_token,profile: auth2.currentUser.get().getBasicProfile() };
        else return { signed_in: false };
    };     


}])

   .config(function($stateProvider, $urlRouterProvider, $locationProvider) {

       $locationProvider.html5Mode(true);
       $urlRouterProvider.otherwise('/cloud');



       var guest = ['$q', '$rootScope', '$stateParams', 'googleService', function ($q, $rootScope, $stateParams, googleService) { 

           var deferred = $q.defer(); 
           googleService.load().then(function(){
               googleService.isSignedIn(gapi.auth2.getAuthInstance()).then(function(r){ 
                   if(r) deferred.reject(); 
                   else deferred.resolve(); 
               });   
           });



           return deferred.promise; 
       }];

       var authenticated = ['$q', '$rootScope', '$stateParams', 'googleService', function ($q, $rootScope, $stateParams, googleService) { 

           var deferred = $q.defer(); 

           googleService.load().then(function(){
               googleService.getProfile(gapi.auth2.getAuthInstance()).then(function(p) { 
                   if(p.signed_in) { 
                       deferred.resolve(); 
                       localStorage['access_token'] = p.access_token;
                       $rootScope.profile = p.profile; 
                   } else deferred.reject(); 
               });   
           });            

           return deferred.promise; 
       }];

       $stateProvider

       .state('login', {
           url: '/',
           views: { 'main': { templateUrl: 'pages/templates/login.html', controller: 'login' } },
           resolve: { authenticated: guest }
       })

       .state('cloud', {
           url: '/cloud',
           views: { 'main': { templateUrl: 'pages/templates/cloud.html', controller: 'cloud' } },
           resolve: { authenticated: authenticated }
       })

   })

   .controller('login', ['$rootScope', '$scope', '$q', '$state', 'googleService', function ($rootScope, $scope, $q, $state, googleService) {
       $scope.options = { 'onsuccess': function(response) { $state.go('cloud'); } }
   }])

   .controller('cloud', ['$rootScope', '$scope', '$timeout', '$http', '$httpParamSerializerJQLike', function ($rootScope, $scope, $timeout, $http, $httpParamSerializerJQLike) { 

   }]);