|
4 | 4 |
|
5 | 5 | // Define a service which provides user authentication and management. |
6 | 6 | angular.module('firebase').factory('$firebaseAuth', [ |
7 | | - '$q', '$firebaseUtils', '$log', function($q, $firebaseUtils, $log) { |
| 7 | + '$q', '$firebaseUtils', function($q, $firebaseUtils) { |
8 | 8 | /** |
9 | 9 | * This factory returns an object allowing you to manage the client's authentication state. |
10 | 10 | * |
|
13 | 13 | * authentication state, and managing users. |
14 | 14 | */ |
15 | 15 | return function(ref) { |
16 | | - var auth = new FirebaseAuth($q, $firebaseUtils, $log, ref); |
| 16 | + var auth = new FirebaseAuth($q, $firebaseUtils, ref); |
17 | 17 | return auth.construct(); |
18 | 18 | }; |
19 | 19 | } |
20 | 20 | ]); |
21 | 21 |
|
22 | | - FirebaseAuth = function($q, $firebaseUtils, $log, ref) { |
| 22 | + FirebaseAuth = function($q, $firebaseUtils, ref) { |
23 | 23 | this._q = $q; |
24 | 24 | this._utils = $firebaseUtils; |
25 | | - this._log = $log; |
26 | | - |
27 | 25 | if (typeof ref === 'string') { |
28 | 26 | throw new Error('Please provide a Firebase reference instead of a URL when creating a `$firebaseAuth` object.'); |
29 | 27 | } |
30 | 28 | this._ref = ref; |
| 29 | + this._initialAuthResolver = this._initAuthResolver(); |
31 | 30 | }; |
32 | 31 |
|
33 | 32 | FirebaseAuth.prototype = { |
|
246 | 245 | * rejected if the client is unauthenticated and rejectIfAuthDataIsNull is true. |
247 | 246 | */ |
248 | 247 | _routerMethodOnAuthPromise: function(rejectIfAuthDataIsNull) { |
249 | | - var ref = this._ref; |
| 248 | + var ref = this._ref, utils = this._utils; |
| 249 | + // wait for the initial auth state to resolve; on page load we have to request auth state |
| 250 | + // asynchronously so we don't want to resolve router methods or flash the wrong state |
| 251 | + return this._initialAuthResolver.then(function() { |
| 252 | + // auth state may change in the future so rather than depend on the initially resolved state |
| 253 | + // we also check the auth data (synchronously) if a new promise is requested, ensuring we resolve |
| 254 | + // to the current auth state and not a stale/initial state (see https://github.com/firebase/angularfire/issues/590) |
| 255 | + var authData = ref.getAuth(), res = null; |
| 256 | + if (authData !== null) { |
| 257 | + res = utils.resolve(authData); |
| 258 | + } |
| 259 | + else if (rejectIfAuthDataIsNull) { |
| 260 | + res = utils.reject("AUTH_REQUIRED"); |
| 261 | + } |
| 262 | + else { |
| 263 | + res = utils.resolve(null); |
| 264 | + } |
| 265 | + return res; |
| 266 | + }); |
| 267 | + }, |
250 | 268 |
|
251 | | - return this._utils.promise(function(resolve,reject){ |
252 | | - function callback(authData) { |
| 269 | + /** |
| 270 | + * Helper that returns a promise which resolves when the initial auth state has been |
| 271 | + * fetch from the Firebase server. This never rejects and resolves to undefined. |
| 272 | + * |
| 273 | + * @return {Promise<Object>} A promise fulfilled when the server returns initial auth state. |
| 274 | + */ |
| 275 | + _initAuthResolver: function() { |
| 276 | + var ref = this._ref; |
| 277 | + return this._utils.promise(function(resolve) { |
| 278 | + function callback() { |
253 | 279 | // Turn off this onAuth() callback since we just needed to get the authentication data once. |
254 | 280 | ref.offAuth(callback); |
255 | | - |
256 | | - if (authData !== null) { |
257 | | - resolve(authData); |
258 | | - return; |
259 | | - } |
260 | | - else if (rejectIfAuthDataIsNull) { |
261 | | - reject("AUTH_REQUIRED"); |
262 | | - return; |
263 | | - } |
264 | | - else { |
265 | | - resolve(null); |
266 | | - return; |
267 | | - } |
| 281 | + resolve(); |
268 | 282 | } |
269 | | - |
270 | 283 | ref.onAuth(callback); |
271 | 284 | }); |
272 | 285 | }, |
|
0 commit comments