6

我正在寻找一种可靠的方法来在我的所有控制器中使用“当前用户 ID”。使用:Firebase 简单登录:电子邮件/密码验证

我的 ida:我需要一个可以注入控制器的“工厂”,以使“当前用户 ID”始终可用。

我想出了这段代码:

    app.factory('User', ['angularFire',

    //Get Current UserID

    function(angularFire){

        console.log ('FACTORY: User');
            var currentUser = {};
            var ReturnStr = '';
        var ref = new Firebase("https://myFIREBASE.firebaseio.com/");
        var authClient = new FirebaseAuthClient(ref, function (err, user) {

            if (err) {
                    ReturnStr = 'FACTORY: User Error: ' + err; 
                console.log (ReturnStr);
                        //var User = ReturnStr;
            } else if (user) {
                console.log ('FACTORY: User: Login successfully:');
                console.log (user);
                currentUser = user;
            } else {
                //console.log ('-----------User: Logged Out ---------------');
                    ReturnStr = 'FACTORY: Logged out: Redirect to Login'; 
                console.log (ReturnStr);
                window.location.href = "/login.php";
            }
        });

    return currentUser;
        }
]);

我最简单的控制器看起来像:

function ToDoCtrl($scope, User) {
    $scope.MyUser = User;
    $scope.MyUser.test = 'Test';
}

在 HTML(角度部分)中,我有:

<h2>{{MyUser.id}}</h2>
<h2>{{MyUser.email}}</h2>
<h2>{{MyUser.provider}}</h2>
<h2>{{MyUser.test}}</h2>

=> id、email、provider 是“未定义的”。在控制台中,我看到“工厂:用户:成功登录:”,用户正确 - 对象。

=> 异步加载数据问题?

我也尝试过(没有运气):

        $timeout(function () {
        currentUser = user;
        }

这样的工厂将非常有用!感谢您为我指明正确的方向!

编辑 1.1: 现在,使用 $rootscope hack

=> 相同的效果 - mycontroller 太快 - 工厂速度太慢。

app.factory('User', ['$rootScope', '$timeout', 'angularFire',

    //Aktueller Benutzer auslesen

    function($rootScope, $timeout, angularFire){

        console.log ('FACTORY: User');
            var currentUser = {};
            var ReturnStr = '';
        var ref = new Firebase("https://openpsychotherapy.firebaseio.com/");
        var authClient = new FirebaseAuthClient(ref, function (err, user) {

            if (err) {
                    ReturnStr = 'FACTORY: User Error: ' + err; 
                console.log (ReturnStr);
                        //var User = ReturnStr;
            } else if (user) {
                console.log ('FACTORY: User: Login successfully:');
                        //currentUser = user;

            $timeout(function () {
                        ReturnStr = 'FACTORY: Inside timout'; 
                  console.log (ReturnStr);

                            currentUser = user;
                  console.log (currentUser);

                $rootScope.myUser = user;
                $rootScope.myUserID = user.id;
                $rootScope.loggedIn = true;
                            $rootScope.$apply();

                  return currentUser;
            });


            } else {
                //console.log ('-----------User: Logged Out ---------------');
                    ReturnStr = 'FACTORY: Logged out: Redirect to Login'; 
                console.log (ReturnStr);
                        //var User = ReturnStr;
                window.location.href = "/login.php";
            }
        });

    return currentUser;
        }
]);

TANHKS 提供任何有用的建议!想知道其他人如何解决这个问题!

4

4 回答 4

14

所以这是我对这个确切问题的解决方案。我正在为我的 Angular 应用程序使用 Firebase、FirebaseAuthClient 和 angularFire。我的登录系统遇到了同样的情况,您无法将 $scope 注入工厂,因此我想出了一个控制器,它使用工厂来检索、添加、更新和删除事物的方法。在控制器中,我有我的 firebaseAuth 东西,用户值的设置,以及我分配给它的范围的引用。用户登录后,他们将被重定向到另一个位置,此时 app.js 文件在该地址位置使用子控制器接管。

我的登录也使用 localStorage,因此登录将持续存在,您可以刷新而不必继续登录,您可以轻松地将其更改为 cookie 或 sessionStorage。

如果您选择使用这种方法,这将需要特别适应您的需求,无论如何它都非常复杂,但这对我来说非常可靠,我不再需要担心 firebaseAuth 或 angularFire 的东西了我的工厂都设置为来回传递数据。我只是在做 angularJS 的东西,主要是用指令。所以这是我的代码。

注意:这将需要修改,并且有些东西将是伪的或开放式的,您可以根据自己的需要来确定。

AuthCtrl.js

'use strict';

angular.module('YOUR_APP', []).
controller('AuthCtrl', [
'$scope',
'$location',
'angularFire',
'fireFactory',

function AuthCtrl($scope, $location, angularFire, fireFactory) {
    // FirebaseAuth callback
    $scope.authCallback = function(error, user) {
        if (error) {
            console.log('error: ', error.code);
            /*if (error.code === 'EXPIRED_TOKEN') {
                $location.path('/');
            }*/
        } else if (user) {
            console.log('Logged In', $scope);
            // Store the auth token
            localStorage.setItem('token', user.firebaseAuthToken);
            $scope.isLoggedIn = true;

            $scope.userId = user.id;

            // Set the userRef and add user child refs once
            $scope.userRef = fireFactory.firebaseRef('users').child(user.id);
            $scope.userRef.once('value', function(data) {
                // Set the userRef children if this is first login
                var val = data.val();
                var info = {
                    userId: user.id,
                    name: user.name
                };
                // Use snapshot value if not first login
                if (val) {
                    info = val;
                }
                $scope.userRef.set(info); // set user child data once
            });

            $location.path('/user/' + $scope.userRef.name());
        } else {
            localStorage.clear();
            $scope.isLoggedIn = false;
            $location.path('/');
        }
    };

    var authClient = new FirebaseAuthClient(fireFactory.firebaseRef('users'), $scope.authCallback);

    $scope.login = function(provider) {
        $scope.token = localStorage.getItem('token');
        var options = {
            'rememberMe': true
        };
        provider = 'twitter';

        if ($scope.token) {
            console.log('login with token', $scope.token);
            fireFactory.firebaseRef('users').auth($scope.token, $scope.authCallback);
        } else {
            console.log('login with authClient');
            authClient.login(provider, options);
        }
    };

    $scope.logout = function() {
        localStorage.clear();
        authClient.logout();
        $location.path('/');
    };
}

]);

现在是漂亮而简单但可重复使用的工厂。您需要为您的应用设置 Firebase 路径,以便 baseUrl 变量能够正常工作。

火工厂.js

'use strict';
angular.module('YOUR_APP').
factory('fireFactory', [
function fireFactory() {
    return {
        firebaseRef: function(path) {
            var baseUrl = 'https://YOUR_FIREBASE_PATH.firebaseio.com';
            path = (path !== '') ?  baseUrl + '/' + path : baseUrl;
            return new Firebase(path);
        }
    };
}

]);

信息

您只给工厂一个路径引用,例如“用户”,它将用作您要存储用户数据的完整路径引用的一部分。

fireFactory.firebaseRef('users')

一旦您为用户设置了参考集,就无需再次设置它们,只需使用现有数据和 .auth() 即可。此外,如果 localStorage 中有一个现有的“令牌”,它也会使用它来 auth() 用户。

否则,它将 login() 用户并弹出打开 Oauth 窗口,让他们使用您提供的任何选项来执行此操作。

在 Firebase/FirebaseAuthClient 和 angularFire 方面,我花了很多时间,很多天甚至几个月来寻找比这更好的东西。以 Firebase API 和 FireAuth API 的方式,在将它们与 angularFire 一起使用时,让它们相互配合是非常烦人的。这非常令人沮丧,但我终于克服了它。

如果您想查看我的应用程序的代码并了解我是如何更完整地完成这些事情的,您可以在我的 Webernote github repo 的这个分支中找到它。

随意派生它,在本地安装和运行它,或者即使你愿意也可以为它做出贡献。我可以自己使用一些帮助:)

希望这对你有帮助!!

于 2013-06-24T09:09:10.653 回答
1

这是我的做法。

首先,我有我的 firebase 身份验证服务(我没有使用 Angularfire),它会调用 Singly 来处理登录。当用户状态改变时,它会广播一个事件。

p4pApp.factory('firebaseAuth', function($rootScope, singlyAuth) {
var auth = {},
    FBref = new Firebase(p4pApp.FIREBASEPATH);

auth.login = function(service) {
    singlyAuth.login(service);
};

auth.logout = function() {
    FBref.unauth();
    auth.user = null;
    auth.broadcastAuthEvent();
};

auth.broadcastAuthEvent = function() {
    $rootScope.$broadcast('authEvent');
};

auth.authWithToken = function(token) {
    if (token !== undefined) {
        FBref.auth(token, function(error, authData) {
            if(!error) {
                auth.user = authData.auth.account;
                auth.broadcastAuthEvent();
            } else {
                auth.user = null;
                auth.broadcastAuthEvent();
            }
        }, function(error) {
            auth.user = null;
            auth.broadcastAuthEvent();
        });
    }
};

return auth;
});

然后我有一个负责授权状态的“顶级”控制器。

var AuthCtrl = function($scope, firebaseAuth, singlyAuth, firebase, user) {
$scope.user = null;

$scope.logout = function() {
    firebaseAuth.logout();
};

$scope.isLoggedIn = function() {
    return !!$scope.user;   
};

// src: Alex Vanston (https://coderwall.com/p/ngisma)
$scope.safeApply = function(fn) {
    var phase = this.$root.$$phase;
    if (phase == '$apply' || phase == '$digest') {
        if(fn && (typeof(fn) === 'function')) {
            fn();
        }
    } else {
        this.$apply(fn);
    }
};

$scope.$on('authEvent', function() {
    $scope.safeApply(function() {
        $scope.user = firebaseAuth.user;
    });

    user.setID(firebaseAuth.user);

    if (firebaseAuth.user) {
        firebase.fetch(['users', firebaseAuth.user], function(results) {
            if (results) {
                user.setData(results);
            } else {
                results = {};
                results.createdAt = DateTimeStamp();
            }

            results.lastLogin = DateTimeStamp();

            firebase.set('users', firebaseAuth.user, results);
        });     
    } else {
        user.clearData();
    }
});
};

最后,我使用专门的用户服务来维护用户状态。(仍在开发中)

p4pApp.factory('user', function() {
var userService = {}, user={};

user.data = {};

userService.setID = function(id) {
    user.id = id;
};

userService.getID = function() {
    return user.id;
};

userService.setData = function(data) {
    user.data = data || {};
};

userService.getData = function() {
    return user.data;
};

userService.clearData = function() {
    user.data = {};
};

userService.setDataField = function(field, data) {
    user.data[field] = data;
};

userService.clearDataField = function(field) {
    delete user.data[field];
};

userService.pushData = function(key, data) {
    if (typeof(key) === 'string') {
        user.data[key] = data;
    } else {
        _.reduce(key, function(obj, child, index, list) {
            obj[child] = obj[child] || {};

            if (index == list.length-1) {
                obj[child] = data;
            }

            return obj[child];
        }, user.data);          
    }
};

userService.deleteData = function(key) {
    if (typeof(key) === 'string') {
        delete user.data[key];
    } else {
        _.reduce(key, function(obj, child, index, list) {
            obj[child] = obj[child] || {};

            if (index == list.length-1) {
                delete obj[child];
                return;
            }

            return obj[child];
        }, user.data);          
    }
};

return userService;
});
于 2013-06-24T08:08:51.760 回答
0

这很可能是由于调用的异步性质。要修复它,您必须

  • 注入$scope到工厂函数中(类似于angularFire依赖)
  • $scope.$apply()分配后 使用currentUser = user;
于 2013-06-23T10:06:34.317 回答
0

另一个适合我的解决方案:

account.service.js

(function() {
    'use strict';

    angular
        .module('app.account')
        .factory('Account', Account);

    Account.$inject = [
        '$firebaseAuth',
        '$firebaseObject'
    ];

    /* @ngInject */
    function Account(
        $firebaseAuth,
        $firebaseObject,
    ) {
        var firebaseRef = new Firebase('https://<<-- MY_FIREBASE -->>.firebaseio.com');
        var authObj = $firebaseAuth(firebaseRef);
        var service = {
            userInfo: null
        };
        activate();
        return service;

        ////////////////

        function activate() {
            // Add listeners for authentication state changes
            authObj.$onAuth(function(authData) {
                if (authData) {
                    // Load the userInfo
                    loadUserInfo(authData);
                } else {
                    // Destroy the userInfo Object if one exists
                    if (service.userInfo) {
                        service.userInfo.$destroy();
                        service.userInfo = null;
                    }
                }
            });
        }

        function loadUserInfo(authData) {
            var userRef = firebaseRef.child('users').child(authData.uid);
            var loadedInfo = $firebaseObject(userRef);

            loadedInfo.$loaded()
            .then(function() {
                service.userInfo = loadedInfo;
            })
            .catch(function(error) {
                switch (error.code) {
                    case 'PERMISSION_DENIED':
                        alert('You don\'t have the permission to see that data.');
                        break;
                    default:
                        alert('Couldn\'t load the user info.');
                }
            });
        }
    }
})();

一些组件.controller.js

(function() {
    'use strict';

    angular
        .module('app')
        .controller('SomeController', SomeController);

    SomeController.$inject = [
        'Account'
    ];

    /* @ngInject */
    function SomeController(
        Account
    ) {
        var vm = this;

        vm.userInfo     = userInfo;

        ////////////////

        function userInfo() {
            return Account.userInfo;
        }

        ...
    }
})();

一些组件.html

...
<div class="user-id">
    {{vm.userInfo().id}}
<div>
...
于 2015-10-13T21:46:23.170 回答