web-dev-qa-db-ja.com

AngularJS-ユーザーがログインしている場合、ナビゲーションアイテムの表示/非表示

Express、node.js、MongoDBをMongoose経由で使用する単一ページのAngularJSアプリがあります。ユーザー管理/認証にPassportを使用します。

ユーザーがログインしているかどうかに基づいてnavbarアイテムを変更したいのですが。私はそれを実装する方法を理解するのに苦労しています。

ユーザーがhttpリクエストを介してログインしているかどうかを確認します。

server.js

_app.get('/checklogin',function(req,res){
  if (req.user)
    res.send(true);
  else
    res.send(false);
_

フロントエンドには、Angularの_$http_サービスを使用してこれを呼び出すNavControllerがあります。

NavController.js

_angular.module('NavCtrl',[]).controller('NavController',function($scope,$http) {

    $scope.loggedIn = false;

    $scope.isLoggedIn = function() {

      $http.get('/checklogin')
        .success(function(data) {
          console.log(data);
          if (data === true)
            $scope.loggedIn = true;
          else
            $scope.loggedIn = false;
        })
        .error(function(data) {
          console.log('error: ' + data);
        });
    };
};
_

私のナビゲーションでは、_ng-show_と_ng-hide_を使用して、どの選択を表示するかを決定しています。また、ユーザーがnav項目をクリックしたときにisLoggedIn()関数をトリガーし、クリックごとにユーザーがログインしているかどうかを確認します。

index.html

_<nav class="navbar navbar-inverse" role="navigation">
  <div class="navbar-header">
    <a class="navbar-brand" href="/">Home</a>
  </div>
  <ul class="nav navbar-nav">
    <li ng-hide="loggedIn" ng-click="isLoggedIn()">
      <a href="/login">Login</a>
    </li>
    <li ng-hide="loggedIn" ng-click="isLoggedIn()">
      <a href="/signup">Sign up</a>
    </li>
    <li ng-show="loggedIn" ng-click="logOut(); isLoggedIn()">
      <a href="#">Log out</a>
    </li>
  </ul>
</nav>
_

問題

私のアプリには、ユーザーがNavControllerのスコープ外にログイン/ログアウトできる他の場所があります。たとえば、LoginControllerに対応するログインページにログインボタンがあります。これをアプリ全体に実装するより良い方法があると思います。

_req.user_がバックエンドでtrueであるかどうかを「監視」し、それに応じてナビアイテムを応答させるにはどうすればよいですか?

17
Ryan Tuck

$rootScopeを使用して、アプリ全体で情報を共有できます。

.controller('NavController',function($scope,$http, $rootScope) {

    $scope.isLoggedIn = function() {

      $http.get('/checklogin')
        .success(function(data) {
          console.log(data);
          $rootScope.loggedIn = data;
        })
        .error(function(data) {
          console.log('error: ' + data);
        });
    };
};

これで、上記のコードで行われたのと同じ方法で$rootScope.loggedInにアクセスして、アプリの他の場所からloggedInの値を変更できます。

つまり、関連するコードをサービスとディレクティブに抽象化する必要があります。これにより、$rootScope.loggedInの状態を処理、ログイン、ログアウト、および状態管理するための中心的な場所を1つ持つことができます。あなたが関連するコードの残りを投稿するなら、私はより具体的な答えであなたを助けることができます

11
Nicolás Straub

ユーザーが正常にログインすると、そのイベントをブロードキャストできます。また、ユーザーがログインしている場合にサーバーをポーリングし続ける必要はありません。有効なセッションがあるかどうかを示す変数をメモリに保持できます。サーバー側で設定されるトークンベースの認証を使用できます。

services.factory('UserService', ['$resource',                                        
  function($resource){

    // represents guest user - not logged
    var user = {
        firstName : 'guest',
        lastName : 'user',
        preferredCurrency : "USD",
        shoppingCart : {
            totalItems : 0,
            total : 0
        },                                                  
    };

    var resource = function() {
        return $resource('/myapp/rest/user/:id', 
            { id: "@id"}
    )};

    return {
        getResource: function() { 
            return resource;
        },

        getCurrentUser: function() {
            return user;
        },

        setCurrentUser: function(userObj) {
            user = userObj;
        },

        loadUser: function(id) {
            user = resource.get(id);
        }
    }

  }]);

services.factory('AuthService', ['$resource', '$rootScope', '$http', '$location', 'AuthenticationService', 
  function ($resource, $rootScope, $http, $location, AuthenticationService) {
    var authFactory = {
        authData: undefined       
    };

    authFactory.getAuthData = function () {
        return this.authData;
    };

    authFactory.setAuthData = function (authData) {
        this.authData = {
            authId: authData.authId,
            authToken: authData.authToken,
            authPermission: authData.authPermission
        };
        // broadcast the event to all interested listeners
        $rootScope.$broadcast('authChanged');
    };

    authFactory.isAuthenticated = function () {
        return !angular.isUndefined(this.getAuthData());
    };

    authFactory.login = function (user, functionObj) {
        return AuthenticationService.login(user, functionObj);          
    };

    return authFactory;
}]);

services.factory('AuthenticationService', ['$resource',
  function($resource){
    return $resource('/myapp/rest/auth/', 
            {},
            {
              'login': { method: "POST" }
            }               
    );
  }]);          

services.factory('authHttpRequestInterceptor', ['$injector',  
 function ($injector) {
    var authHttpRequestInterceptor = {
        request: function ($request) {
            var authFactory = $injector.get('AuthService');
            if (authFactory.isAuthenticated()) {
                $request.headers['auth-id'] = authFactory.getAuthData().authId;
                $request.headers['auth-token'] = authFactory.getAuthData().authToken;
            }
            return $request;
        }
    };

    return authHttpRequestInterceptor;
}]);

コントローラ:

controllers.controller('LoginCtrl', ['$scope', '$rootScope', 'AuthService', 'UserService', 
  function LoginCtrl($scope, $rootScope, AuthService, UserService) {
    $scope.login = function () {
        AuthService.login($scope.userInfo, function (data) {
            AuthService.setAuthData(data);
            // set user info on user service to reflect on all UI components
            UserService.setCurrentUser(data.user);
            $location.path('/home/');               
        });
    };

    $scope.isLoggedIn = function () {
        return AuthService.isAuthenticated();
    }

    $scope.user = UserService.getCurrentUser();         
}])
6
guilhebl

EJSなどのテンプレートライブラリを使用して、ユーザーのセッションデータをindex.html内に追加できます。

Ejsミドルウェアを追加するだけです。

var ejs = require('ejs');
// Register ejs as .html.
app.engine('.html', ejs.__express);

そして、index.htmlを返すときに、セッションデータを応答にレンダリングします。

            res.render( "/index.html", {
                session : {
                    user_data : JSON.stringify(req.user)
                }

            });

これで、index.htmlのこのデータにアクセスできるようになりました。これをAngular app。にロードする必要があります。 preload-resource の例を使用しましたが、独自の方法を使用できます。

0
yotamsha

現在のセッション外でログインを保持したい場合は、$ localStorageを使用することもできます。このライブラリは、このような状況に非常に役立つことがわかりました。 ( https://github.com/grevory/angular-local-storage

0
Jonathan