强制使用Ionic显示日志页面

时间:2015-09-16 07:05:41

标签: angularjs parse-platform ionic-framework

我目前正在使用Ionic开发一个应用程序,我想知道在没有用户登录的情况下,将登录页面显示为弹出窗口的最佳方法是什么。

我希望应用程序在启动时和用户更改页面时检查当前用户。如果ion-header-bar,则会显示登录页面。该应用应该被锁定"在登录页面上,直到用户登录/创建帐户。 (我正在使用Parse.com JS创建/登录用户)

我目前在页面顶部有checkLogedUser() == null,并且认为我可以将ng-controller的所有逻辑放在标题的$scope.$on( "$ionicView.enter", ...内。

但是,如果我在HeaderController中使用$ionicView.enter,则在更改页面时似乎不会触发$ionicView.enter。我有一个标题的控制器和每个页面的一个控制器,所以我在同一页面上总是有两个控制器,我不确定是否会导致问题并且HeaderController被触发页面控制器而不是在页眉控制器和页面控制器上都被触发。此外,我认为这可能是一个缓存问题,但我不知道如何停用$stateProvider的缓存,因为标题未在ion-header-bar中声明,因为它不是一个页面本身只是一个ng-controller angular.module('starter', ['ionic', **'app.services'**]) .run(function($ionicPlatform, $rootScope, **authService**) { $ionicPlatform.ready(function() { if(window.cordova && window.cordova.plugins.Keyboard) { cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); } if(window.StatusBar) { StatusBar.styleDefault(); } $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) { console.log("$rootScope => $stateChangeStart => " + toState.name || ''); if (toState.data && angular.isObject(toState.data)) { if (toState.data.requireLogin && !authService.isUserLoggedIn()) { event.preventDefault(); $state.go("login"); } } }); }); })

此外,可能有更好的方法,我稍微尝试使用服务,但没有任何运气。

带有工作代码的EDIT2:

我已将$ rootScope。$放在$ ionicPlatform.ready(function(){...})部分中。我的离子app.js就是这样开始的:

public void buttonAppClick() {
    final PackageManager pm = getActivity().getPackageManager();
    //get a list of installed apps.
    List<ApplicationInfo> packages = pm.getInstalledApplications(PackageManager.GET_META_DATA);
    outputTextView.setText("");
    for (ApplicationInfo packageInfo : packages) {
        try {
            String packageName = packageInfo.packageName;
            outputTextView.append("Apk Path : " + packageInfo.sourceDir + "\n");
            PackageInfo pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);

            Signature sig = pi.signatures[0];
            String md5Fingerprint = doFingerprint(sig.toByteArray(), "MD5");
            Log.d(TAG_HOME, "MD5 : " + packageInfo.sourceDir + md5Fingerprint);
            outputTextView.append("MD5 : " + md5Fingerprint + "\n");
            outputTextView.append("\n");
        }
        catch (Exception e) {
            Log.e(TAG_HOME, e.getMessage());
        }
    }
}

protected static String doFingerprint(byte[] certificateBytes, String algorithm)
        throws Exception {
    MessageDigest md = MessageDigest.getInstance(algorithm);
    md.update(certificateBytes);
    byte[] digest = md.digest();

    String toRet = "";
    for (int i = 0; i < digest.length; i++) {
        if (i != 0)
            toRet += ":";
        int b = digest[i] & 0xff;
        String hex = Integer.toHexString(b);
        if (hex.length() == 1)
            toRet += "0";
        toRet += hex;
    }
    return toRet;
}

然后创建文件app.services.js(来自plunker链接的那个)

1 个答案:

答案 0 :(得分:1)

那里有很多选择,只是在实施方面你喜欢什么。

首先,为什么要为标题设置控制器?我认为你不需要那个 对我而言,最好的方法是使用一种服务,您可以在其中实现逻辑以检查用户,登录和注销,或最终与其他身份验证服务进行交互。

由于您要检查用户是否已登录并在他/她可以访问受保护区域(视图)之前强制其登录,因此最佳选择是管理状态。

您可以做的是将一些自定义数据附加到您的状态对象(ui-router),以便您可以检查该视图是否需要有效用户:

$stateProvider

      .state('home', {
        url: '/home',
        templateUrl: 'home.html',
        controller: 'homeController',
        data: {
          requireLogin: true
        }
      })

      .state('login', {
        url: '/login',
        templateUrl: 'login.html',
        controller: 'loginController',
        data: {
          requireLogin: false
        }
    });

正如您所看到的,我在这里有2个州,​​并且我已经使用一些自定义信息对其进行了扩展:data: {requireLogin: true/false }

现在,我可以使用event stateChangeStart进行一些检查:

$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
    if (toState.data && angular.isObject(toState.data)) {
        if (toState.data.requireLogin && !authService.isUserLoggedIn()) {
            event.preventDefault();
            $state.go("login");
        }
    }
});

每次状态改变都会引发火灾。 如果您要访问的状态(toState)具有扩展数据,并且新状态需要登录,则可以在此处。当然,您需要检查用户是否已登录。

如果用户未登录,您可以重定向到登录页面$state.go("login");

最后一次检查可以使用服务完成:

(function() {

  'use strict';

  angular
    .module('app.services', [])
    .factory('authService', authService);

  authService.$inject = ['$q', '$http'];

  /* @ngInject */
  function authService($q, $http) {

    var service = {
      userLoggedIn: false,
      isUserLoggedIn: isUserLoggedIn,
      login: login,
      logout: logout
    };

    return (service);

    function isUserLoggedIn() {
      return this.userLoggedIn;
    }

    function login(username, password) {
      var deferred = $q.defer();

      this.userLoggedIn = true;

      deferred.resolve(true);

      return deferred.promise;
    }

    function logout() {
      var deferred = $q.defer();

      this.userLoggedIn = false;

      deferred.resolve(true);

      return deferred.promise;
    }
  }
})();

不要害怕风格。我使用了一些您可以找到的最佳实践here

此服务层有一个成员(属性)userLoggedIn和三个方法:

  • isUserLoggedIn(检查用户是否已登录)
  • 登录(登录)
  • 注销(注销)

loginlogout在这里做得不多;只需通过promise返回一个布尔值。我已经使用了一个承诺,即使我不需要它 - 我想 - 在您的实现中,您将使用$http或其他可能与promises一起使用的其他服务层与远程API进行交互。

使用此代码,您的应用程序将能够检查用户是否经过身份验证并将其重定向到登录页面。
现在我们需要一个登录视图:

<ion-view view-title="Autenticazione" cache-view="false">
    <ion-content scroll="false" padding="false">
        <form name="loginForm" ng-submit="login(user)" novalidate>
            <div class="list">
                <div class="item item-divider">Utente</div>
                <label class="item item-input item-stacked-label" ng-class="{ 'has-errors' : loginForm.username.$invalid && !loginForm.username.$pristine, 'no-errors' : loginForm.username.$valid}">
                    <span class="input-label">Username</span>
                    <input type="text" name="username" placeholder="Username" ng-model="user.username" required ng-minlength="3" ng-maxlength='100' />
                </label>
                <label class="item item-input item-stacked-label" ng-class="{ 'has-errors' : loginForm.password.$invalid && !loginForm.password.$pristine, 'no-errors' : loginForm.password.$valid}">
                    <span class="input-label">Password</span>
                    <input type="password" name="password" placeholder="password" ng-model="user.password" required ng-minlength="3" ng-maxlength="100" />
                </label>
            </div>
            <div class="padding">
                <button type="submit" class="button button-block button-positive" ng-disabled="loginForm.$invalid">Login</button>
            </div>
        </form>
    </ion-content>
</ion-view>

这里没什么特别的。它只是一个简单的表单,在将数据提交给登录控制器ng-submit="login(user)"之前进行一些验证检查。

这将是控制器:

.controller('loginController', function($scope, $state, $ionicHistory, authService) {

      $scope.user = {
        username: '',
        password: ''
      };

      $scope.login = function(loginUser)
      {
        authService.login(loginUser.username, loginUser.password)
          .then(function(result){
            alert('login successfull.');

            $ionicHistory.clearHistory();
            $ionicHistory.clearCache();
            $ionicHistory.nextViewOptions({ disableBack: true, disableAnimate: true, historyRoot: true });

            $state.go('home');
          })
          .catch(function(reason){
            alert(reason);
          })
          .finally(function(){
              // do something.
          });
      };
});

登录控制器定义了一个对象用户:

$scope.user = {
    username: '',
    password: ''
};

我将其传递给我的观点并稍后阅读以进行验证 login方法与服务authService交互以执行登录方法。 由于该服务中的方法登录返回一个promise,我需要检查结果。我可以使用.then。 如果登录成功,我只需清除缓存并转到主页设置该页面作为历史记录中的根目录:

.then(function(result){
    alert('login successfull.');

    $ionicHistory.clearHistory();
    $ionicHistory.clearCache();
    $ionicHistory.nextViewOptions({ disableBack: true, disableAnimate: true, historyRoot: true });

    $state.go('home');
})

现在应该再次触发事件stateChangeStart,但这次当询问用户是否已登录authService.isUserLoggedIn()时,服务应该返回。

理解工作原理的最简单方法可能是深入研究运行此plunker的代码。