Angular使用与弹出窗口交互的承诺

时间:2015-05-25 14:06:13

标签: angularjs oauth oauth-2.0 popup angular-promise

我对角色,服务以及对承诺的肯定是新手。我在服务中有一些代码,它可以独立工作,但它很麻烦。如果可能的话,我想把整个事情变成一个承诺,因为这会使它变得超级可行。

我正在使用谷歌进行oAuth身份验证。流程是:

  1. 用户点击"使用Google登录"
  2. 会打开一个弹出窗口,重定向到Googles' Approve'屏幕。
  3. 用户点击'批准'并被重定向(在弹出窗口中)回到我的重定向页面(包括谷歌批准代码)。
  4. 我的重定向页面获取了他从谷歌获得的代码并将其发送到我的后端服务器以从Google兑换代码以交换它以获取访问令牌。
  5. 我的服务器兑换代码并从谷歌获取个人资料信息(并记录用户)并返回我的角度应用可以使用的用户对象。
  6. 返回的用户对象(仍然到达弹出窗口)被返回弹出窗口的开启者,弹出窗口关闭。
  7. 用户现已登录我的应用程序。
  8. 正如您将从代码中看到的,我在发送方窗口中创建(临时)函数作为弹出窗口的回调。这有效,但感觉很乱。此外,我不知道如何将这一切都放在一个承诺中,所以最终我可以将服务称为:

    oAuthService.login().then(
      function(){/*rejoice, we made it*/}, 
      function(){/*Error logging*/};`
    

    这是我的代码:

    'use strict';
    var loginServices = angular.module('loginServices', []);
    
    loginServices.service('oAuthService', ['$http', '$q', 'store', '$rootScope', '$window',
      function($http, $q, store, $rootScope, $window){
    
        //todo: Put data in settings file
        var oAuthRequest = {
          endpoint: 'https://accounts.google.com/o/oauth2/auth',
          clientId: '705441731416-iqd7ubbi7so12k4rvj5pr0frdpoqfo4p.apps.googleusercontent.com',
          scope: 'email profile',
          state: 'MyToken123',
          redirectUri: 'http://localhost/loginadmin/web/oAuthRedirect',
          responseType: 'code',
          approvalPrompt: 'force'
        };
    
        this.oAuthGetApproval = function(){
          //Create Callback functions for the popup
          //This will get called after step 5 completed server side
          window.oAuthUserLogin = function(user, sender){
            store.set('currentUser', user);
            $rootScope.setCurrentUser(user);
            sender.close();
            sender.angular.element('#ctrl').scope().apply();
            //cleanup
            window.oAuthUserLogin = undefined;
            window.oAuthUserLoginError = undefined;
          }
    
          //Err callback
          window.oAuthUserLoginError = function(data, sender){
            console.log('Error');
            console.log(data);
            sender.close();
            //cleanup
            window.oAuthUserLogin = undefined;
            window.oAuthUserLoginError = undefined;
          }
    
          //Open popup (Step 1 and 2 in description)
          var uri = oAuthRequest.endpoint
              + '?scope=' + oAuthRequest.scope
              + '&state=' + oAuthRequest.state
              + '&redirect_uri=' + oAuthRequest.redirectUri
              + '&response_type=' + oAuthRequest.responseType
              + '&client_id=' + oAuthRequest.clientId
              + '&approval_prompt=' + oAuthRequest.approvalPrompt;
    
          $window.open(uri, '', "top=100,left=100,width=500,height=500");
        };
    
        //This gets called the popup (Step 4 in description)
        this.oAuthCompleteLogin = function(code){
          $http.post('http://localhost/covlelogin/web/api/oauth-login', { code: code })
              .success(function (data){
                $window.opener.oAuthUserLogin(data, window);
              })
              .error(function(data){
                $window.opener.oAuthUserLoginError(data, window);
              })
        }
    
      }]);
    

1 个答案:

答案 0 :(得分:3)

我自己想通了。我现在正在使用$interval检查弹出窗口是否返回了一些有用的内容,或者弹出窗口是否已关闭。

'use strict';
var loginServices = angular.module('loginServices', []);

loginServices.service('oAuthService', ['$http', '$q', 'store', '$rootScope', '$window', '$interval',
  function($http, $q, store, $rootScope, $window, $interval){

    //todo: Put data in settings file
    var oAuthRequest = {
      endpoint: 'https://accounts.google.com/o/oauth2/auth',
      clientId: '705441731416-iqd7ubbi7so12k4rvj5pr0frdpoqfo4p.apps.googleusercontent.com',
      scope: 'email profile',
      state: 'MyToken123',
      redirectUri: 'http://localhost/loginadmin/web/oAuthRedirect',
      responseType: 'code',
      approvalPrompt: 'force'
    };

    this.oAuthGetApproval = function(){
      var q = $q.defer();
      //Open popup
      var uri = oAuthRequest.endpoint
          + '?scope=' + oAuthRequest.scope
          + '&state=' + oAuthRequest.state
          + '&redirect_uri=' + oAuthRequest.redirectUri
          + '&response_type=' + oAuthRequest.responseType
          + '&client_id=' + oAuthRequest.clientId
          + '&approval_prompt=' + oAuthRequest.approvalPrompt;

      var popup = $window.open(uri, '', "top=100,left=100,width=500,height=500");

      var popupChecker = $interval(function(){

        if (window.oAuthUser != undefined){
          //The popup put returned a user! Resolve!
          q.resolve(window.oAuthUser);
          popup.close();
          $interval.cancel(popupChecker);
          //Save and apply user locally
          store.set('currentUser', window.oAuthUser);
          $rootScope.setCurrentUser(window.oAuthUser);
          //Cleanup
          window.oAuthUser = undefined;
        }else if (popup.closed){
          $interval.cancel(popupChecker);
          console.log("Error logging in.");
          q.reject();
        }
        console.log('tick');
      }, 1000)

      return q.promise;
    };

    this.oAuthCompleteLogin = function(code){
      $http.post('http://localhost/covlelogin/web/api/oauth-login', { code: code })
          .success(function (data){
            $window.opener.oAuthUser = data;
          })
          .error(function(data){
            $window.close();
          })
    }

  }]);

现在,调用此服务很简单:

oAuthService.oAuthGetApproval().then(
      function(user){
        console.log("Logged in as " + user.name);
      },
      function(){
        console.log("Login did not go well.");
      });