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

3
我是新手,对于Angular、服务和Promise都不熟悉。我在一个服务中有这段代码,它可以单独运行,但很混乱。如果可能的话,我想把整个过程放入Promise中,因为这将使它更加易于操作。
我正在使用Google进行OAuth身份验证,流程如下:
1. 用户点击“使用Google登录”。 2. 弹出窗口打开并重定向到Google的“批准”页面。 3. 用户点击“批准”,并在弹出窗口中被重定向回我的重定向页面(包括Google的批准代码)。 4. 我的重定向页面获取来自Google的代码,并将其发送到我的后端服务器以兑换访问令牌。 5. 我的服务器兑换代码并从Google获取个人资料信息(并记录用户登录),然后返回一个用户对象,供我的Angular应用程序使用。 6. 返回的用户对象(仍在弹出窗口中)被返回给弹出窗口的打开者,并关闭弹出窗口。 7. 用户现在已经在我的应用程序中登录。
正如您从代码中看到的那样,我在发送方窗口中创建了(临时)函数作为弹出窗口的回调。这个方法虽然可行,但感觉很混乱。而且我不知道如何将整个过程放入Promise中,以便最终可以像这样调用服务:
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个回答

4

我自己解决了问题。现在我使用$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.");
      });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接