使用本地存储来存储AngularJS数据

时间:2022-05-29 17:11:50

I am currently using $rootScope to store user information and whether or not the user is logged in. I have tried using $window.localStorage, but with no success. My goal is to have items in my navbar appear through an ng-show once a user is logged on, have their username appear in the navbar, individual user profile view, all users view, etc. I need a persistent login. I have the navbar working with $rootscope, but whenever I try and transition over to $window.localStorage, it fails. Here is the code using $rootScope:

我目前使用$rootScope存储用户信息,以及用户是否登录。我试过使用$window。localStorage,但是没有成功。我的目标是,一旦用户登录,用户的用户名出现在导航条中,个人用户配置文件视图,所有用户视图,等等,我需要一个持久的登录。我有一个使用$rootscope的导航条,但是每当我尝试转换到$window时。localStorage,它失败了。下面是使用$rootScope的代码:

mainModule

mainModule

angular.module('mainModule', [
        'ui.router',
         ...
    ])
    .config(configFunction)
    .run(['$rootScope', '$state', 'Auth', function($rootScope, $state, Auth) {
        $rootScope.$on('$stateChangeStart', function(event, next) {
            if (next.requireAuth && !Auth.getAuthStatus()) {
                console.log('DENY');
                event.preventDefault();
                $state.go('login');
            } else if (Auth.getAuthStatus() || !Auth.getAuthStatus()) {
                console.log('ALLOW');
            }
        });
    }]);

Auth Factory

认证的工厂

angular.module('authModule').factory('Auth', ['$http', '$state', function authFactory($http, $state) {
        var factory = {};

        var loggedIn = false;
        var userData = {};

        factory.getAuthStatus = function() {
            $http.get('/api/v1/auth')
                .success(function(data) {
                    if (data.status == true) {
                        loggedIn = true;
                    } else {
                        loggedIn = false;
                    }
                })
                .error(function(error) {
                    console.log(error);
                    loggedIn = false;
                });
            return loggedIn;
        }

        return factory;
    }]);

Login Controller

登录控制器

function SigninController($scope, $rootScope, $http, $state) {
    $scope.userData = {};

    $scope.loginUser = function() {
        $http.post('api/v1/login', $scope.userData)
            .success((data) => {
                $scope.userData = data.data;
                $rootScope.loggedIn = true;
                $rootScope.userData = data;
                $state.go('home');
            })
            .error((error) => {
                console.log('Error: ' + error);
            });
    };
}

Nav Controller

导航控制器

function NavbarController($scope, Auth) {
    $scope.loggedIn = Auth.getAuthStatus();
}

EDIT EDIT EDIT

编辑编辑编辑

Here is how I am using local storage. These are the only things that changed.

以下是我使用本地存储的方式。这些是唯一改变的东西。

Login Controller

登录控制器

function SigninController($scope, $window, $http, $state) {
    $scope.userData = {};

    $scope.loginUser = function() {
        $http.post('api/v1/login', $scope.userData)
            .success((data) => {
                $scope.userData = data.data;
                $window.localStorage.setItem('userData', angular.toJson(data));
                $window.localStorage.setItem('loggedIn', true);
                $state.go('home');
            })
            .error((error) => {
                console.log('Error: ' + error);
            });
    };
}

Auth Factory

认证的工厂

angular
    .module('authModule')
    .factory('Auth', ['$http', '$window', '$state', function authFactory($http, $window, $state) {
        var factory = {};

        factory.getAuthStatus = function() {
            $http.get('/api/v1/auth')
                .success(function(data) {
                    if (data.status == true) {
                        $window.localStorage.setItem('loggedIn', true);
                    } else {
                        $window.localStorage.setItem('loggedIn', false);
                    }
                })
                .error(function(error) {
                    console.log(error);
                    $window.localStorage.setItem('loggedIn', false);
                });
            return $window.localStorage.getItem('loggedIn');
        }

        return factory;
    }]);

2 个解决方案

#1


2  

I see a potential problem with your use of localStorage.getItem('loggedIn').

我看到您使用localStorage.getItem('loggedIn')时可能出现的问题。

Because localStorage only stores strings, what you get back is actually a stringified version of the boolean that you put in. If the string 'false' gets returned, your check of !Auth.getAuthStatus() in main module for example will always evaluate to boolean false because any non-empty string in JavaScript is "truthy".

因为localStorage只存储字符串,所以返回的实际上是一个stringified版本的布尔值。如果字符串“false”被返回,那么在主模块中,您的check of !Auth.getAuthStatus()将始终对布尔false进行评估,因为JavaScript中的任何非空字符串都是“truthy”。

i.e. !'false' === false (the same as !true === false)

例如!'false' === false(同!true === false一样)

You can get over this by using JSON.parse on the value in localStorage. e.g. JSON.parse(localStorage.getItem('loggedIn')) would parse the string 'false' to the Boolean false.

您可以通过使用JSON来克服这个问题。解析localStorage中的值。例如,JSON.parse(localStorage.getItem('loggedIn'))将字符串'false'解析为Boolean false。

#2


1  

Simply replace $window.localStorage with window.localStorage and you should be fine.

简单地取代美元的窗口。localStorage窗口。本地存储,应该没问题。

For example:

例如:

function SigninController($scope, $window, $http, $state) {
    $scope.userData = {};

    $scope.loginUser = function() {
        $http.post('api/v1/login', $scope.userData)
            .success((data) => {
                $scope.userData = data.data;
                window.localStorage.setItem('userData', angular.toJson(data));
                window.localStorage.setItem('loggedIn', true);
                $state.go('home');
            })
            .error((error) => {
                console.log('Error: ' + error);
            });
    };
}

This being said, storing authenticated status in localStorage (or sessionStorage) is not a good path to go down. Both key/value pairs can be read in the developer pane and then altered (aka spoofed) via the console. A better solution is to return a unique value (GUID) after a successful login and store it in a cookie (set to expire in a short amount of time, like 20 minutes) that can be read on the server and verified there. You can and should use $cookie for this. Your user login state should be controlled server-side, never client-side. The client should always have to prove that it is authenticated.

也就是说,在localStorage(或sessionStorage)中存储经过身份验证的状态不是一个好的路径。可以在developer窗格中读取键/值对,然后通过控制台修改(也称为欺骗)。更好的解决方案是在成功登录后返回一个惟一值(GUID),并将其存储在一个cookie(设置为在短时间内过期,比如20分钟)中,该cookie可以在服务器上读取并在那里进行验证。您可以并且应该为此使用$cookie。用户登录状态应该由服务器端控制,而不是客户端。客户端应该始终证明它是经过验证的。

To persist login, create a service that handles your visitor and let that service handle the login/logout and provide the proof of being logged in. That proof of being logged in should always be a private value that is held internally by the service and not accessible outside of it.

要坚持登录,创建一个处理访问者的服务,并让该服务处理登录/注销并提供登录证明。登录的证明应该始终是服务内部持有的私有值,在服务外部不可访问。

(function () {
    'use strict';

    var visitorModelService = ['$http', function ($http) {
            var loggedIn = false,
                visitorModel = {
                    login:function(){
                        //do login stuff with $http here
                        //set loggedIn to true upon success
                    },
                    loggedIn:function(){
                        return loggedIn;
                    },
                    logout:function(){
                        //do logout stuff with $http here
                        //no matter what, set loggedIn to false
                    }
            };
            return visitorModel;
        }];

    var module = angular.module('models.VisitorModel', []);
    module.factory('VisitorModel', visitorModelService);
}());

Doing this, you can simply check for visitor.loggedIn in your ng-show and have everything centralized. Such as:

这样做,您可以简单地检查访问者。在你的ng节目里的loggedIn,把一切都集中起来。如:

<a ng-click='visitor.logout' ng-show='visitor.loggedIn'>Log Out</a>

Better yet, put the elements that are only visible to authenticated users in a div tag and hide/show them en-mass.

更好的是,将只有经过身份验证的用户才能看到的元素放在div标记中,并将它们隐藏/显示为en-mass。

#1


2  

I see a potential problem with your use of localStorage.getItem('loggedIn').

我看到您使用localStorage.getItem('loggedIn')时可能出现的问题。

Because localStorage only stores strings, what you get back is actually a stringified version of the boolean that you put in. If the string 'false' gets returned, your check of !Auth.getAuthStatus() in main module for example will always evaluate to boolean false because any non-empty string in JavaScript is "truthy".

因为localStorage只存储字符串,所以返回的实际上是一个stringified版本的布尔值。如果字符串“false”被返回,那么在主模块中,您的check of !Auth.getAuthStatus()将始终对布尔false进行评估,因为JavaScript中的任何非空字符串都是“truthy”。

i.e. !'false' === false (the same as !true === false)

例如!'false' === false(同!true === false一样)

You can get over this by using JSON.parse on the value in localStorage. e.g. JSON.parse(localStorage.getItem('loggedIn')) would parse the string 'false' to the Boolean false.

您可以通过使用JSON来克服这个问题。解析localStorage中的值。例如,JSON.parse(localStorage.getItem('loggedIn'))将字符串'false'解析为Boolean false。

#2


1  

Simply replace $window.localStorage with window.localStorage and you should be fine.

简单地取代美元的窗口。localStorage窗口。本地存储,应该没问题。

For example:

例如:

function SigninController($scope, $window, $http, $state) {
    $scope.userData = {};

    $scope.loginUser = function() {
        $http.post('api/v1/login', $scope.userData)
            .success((data) => {
                $scope.userData = data.data;
                window.localStorage.setItem('userData', angular.toJson(data));
                window.localStorage.setItem('loggedIn', true);
                $state.go('home');
            })
            .error((error) => {
                console.log('Error: ' + error);
            });
    };
}

This being said, storing authenticated status in localStorage (or sessionStorage) is not a good path to go down. Both key/value pairs can be read in the developer pane and then altered (aka spoofed) via the console. A better solution is to return a unique value (GUID) after a successful login and store it in a cookie (set to expire in a short amount of time, like 20 minutes) that can be read on the server and verified there. You can and should use $cookie for this. Your user login state should be controlled server-side, never client-side. The client should always have to prove that it is authenticated.

也就是说,在localStorage(或sessionStorage)中存储经过身份验证的状态不是一个好的路径。可以在developer窗格中读取键/值对,然后通过控制台修改(也称为欺骗)。更好的解决方案是在成功登录后返回一个惟一值(GUID),并将其存储在一个cookie(设置为在短时间内过期,比如20分钟)中,该cookie可以在服务器上读取并在那里进行验证。您可以并且应该为此使用$cookie。用户登录状态应该由服务器端控制,而不是客户端。客户端应该始终证明它是经过验证的。

To persist login, create a service that handles your visitor and let that service handle the login/logout and provide the proof of being logged in. That proof of being logged in should always be a private value that is held internally by the service and not accessible outside of it.

要坚持登录,创建一个处理访问者的服务,并让该服务处理登录/注销并提供登录证明。登录的证明应该始终是服务内部持有的私有值,在服务外部不可访问。

(function () {
    'use strict';

    var visitorModelService = ['$http', function ($http) {
            var loggedIn = false,
                visitorModel = {
                    login:function(){
                        //do login stuff with $http here
                        //set loggedIn to true upon success
                    },
                    loggedIn:function(){
                        return loggedIn;
                    },
                    logout:function(){
                        //do logout stuff with $http here
                        //no matter what, set loggedIn to false
                    }
            };
            return visitorModel;
        }];

    var module = angular.module('models.VisitorModel', []);
    module.factory('VisitorModel', visitorModelService);
}());

Doing this, you can simply check for visitor.loggedIn in your ng-show and have everything centralized. Such as:

这样做,您可以简单地检查访问者。在你的ng节目里的loggedIn,把一切都集中起来。如:

<a ng-click='visitor.logout' ng-show='visitor.loggedIn'>Log Out</a>

Better yet, put the elements that are only visible to authenticated users in a div tag and hide/show them en-mass.

更好的是,将只有经过身份验证的用户才能看到的元素放在div标记中,并将它们隐藏/显示为en-mass。