My app has 2 pages: main.html
and login.html
.
When not authenticated users go to /main
they should be redirected to /login
.
The problem is that main.html
is rendered first, and after a second or so, when user authentication fails, login.html
is rendered.
How could I prevent from main.html
to be rendered until authentication succeeds?
Here is the relevant code (CoffeeScript):
angular.module('myApp', [...])
.config(['$routeProvider', ($routeProvider) ->
$routeProvider.when '/login',
templateUrl: 'html/login.html'
controller: LoginController
$routeProvider.otherwise
templateUrl: 'html/main.html'
controller: MainController
])
.run(['$rootScope', '$location', 'appService', ($rootScope, $location, app) ->
$rootScope.$on '$locationChangeStart', (event, newValue, oldValue) ->
return if newValue == '/login'
$.when(app.authenticate()).fail ->
$location.path '/login'
$rootScope.$apply()
])
angular.module('myApp.services').factory 'appService' , () ->
rootRef = new Firebase('https://myapp.firebaseio.com')
user: null
authenticate: ->
deferred = $.Deferred()
authClient = new FirebaseAuthClient rootRef, (error, user) =>
if error
# An error occurred while attempting login
@user = null
deferred.reject()
else if user
# User authenticated with Firebase
@user = user
deferred.resolve()
else
# User is logged out
@user = null
deferred.reject()
deferred.promise()
Well, I don't serve the template (in your case main.html
) until the user is authenticated. I have a customized function on server for serving templates, which checks if the user is authenticated. If in the function I find out the user is not logged in, it returns response with 401 status code. In angular code I then hold the request until the authentication and then ask for the template again.
I was inspired to do this by this post: http://www.espeo.pl/2012/02/26/authentication-in-angularjs-application
My solution to the same requirement was to define the following watch:
$rootScope.$watch(
function() {
return $location.path();
},
function(newValue, oldValue) {
if (newValue != '/login' && user is not logged in) {
$location.path('/login');
}
},
true);
in a controller associated with the body element of the index page (i. e. the page containing the ng-view
directive).
One option is to hide the normal DOM and show an "Authenticating..." message, maybe with a spinner, to give the user some idea of why he/she is sitting there waiting for something to happen. In main.html, include something like:
<spinner ng-hide="appService.wrapper.user"></spinner>
<!-- everything else ng-show="appService.wrapper.user" -->
where <spinner></spinner>
is an Angular directive that is replaced by your custom "Authenticating..." message, and user
is a variable your appService makes available to MainController
. Note that you may need to wrap user
in an object within appService, like so:
.service('appService', function() {
var wrapper = {
user: null
};
function authenticate() {
// start the authentication and return the promise,
// but modify wrapper.user instead of user
}
return wrapper;
});
You'll also need to store either appService
or appService.wrapper
in the $scope
variable of your MainController
.
来源:https://stackoverflow.com/questions/15024253/angularjs-how-to-hide-the-template-content-until-user-is-authenticated