Forward to a specific page after logging in - angularjs

I have an Angular app in which a user is redirected to the login page if they try to access a page for which they need to be authenticated. Currently, when the user is successfully authenticated from the login page, they are redirected to a default start page. The change that I need to make is this:
When a user is attempting to browse to a specific page and needs to login, after the user has successfully logged in, the site should forward the user to the page they wanted.
Any ideas on how this can be done in AngularJS?

OK, after some research I was able to come up with the solution below:
In app.js I added the following run method.
angular.module('MainModule', [])
...
.run(function($rootScope, $location, UserService) {
$rootScope.$on("$locationChangeStart", function(event, next, current) {
if ((!UserService.isUserLoggedIn()) && ($location.path() !== '/login')) {
$rootScope.postLoginRoute = $location.path();
$location.path('/login').replace();
}
});
});
In my loginController I was able to redirect the user to the page they desire as follows:
function loginController($scope, $location, UserService, $rootScope){
$scope.submit = function() {
if(UserService.validateCredentials($scope.username, $scope.password)){
if($rootScope.postLoginRoute){
$location.url($rootScope.postLoginRoute);
} else{
$location.path('/defaultPage');
}
$rootScope.postLoginRoute = null;
}
}
};

Related

How can i redirect to another page without loading the current page in angularjs

I want to redirect to another page without loading the currentpage.
let me explain my task. I am having user login condition.
If the user has not login and he tries to enter the URL directly EX("localhost/sample.html") means it will come to login page. For me this condition is working nicely.
First sample.html page open and then only it will redirect to login. The user able to see the Data in sample.html.
var logincheck = function () {
debugger;
$http.get('loggedin').success(function (user) {
alert(user);
// Authenticated
if (user != '0') {
refresh();
return;
}
// Not Authenticated
else {
$window.location.href = '/';
}
});
};
logincheck();
Is there any way to go login page without loading the sample.html page.
A interesting way do to this is by checking this condition in a $route event. For example, you can write this code in your app.run:
$rootScope.$on('$routeChangeStart', function(event, next, current) {
if(next.$$route && userNotAuthenticated) {
$location.href('/');
}
});
The advantage is that it will work for your whole app, you won't have to write code for each page.
In your main controller (the one attached to index) you should do a login check and set a variable to true/false. In your controller do a check on this variable, and do a $state.go() if user is not logged in.
Use ng-cloak directive in your index file where you attach your main controller like:
<body ng-controller="mainController" ng-cloak>
You can read up on ng-cloak here
This is how you can do it.
Whenever your angular app is boots, it runs the run function. So attach a location change listener in that function like below
App.run(['$rootScope', '$http', '$urlRouter', function($rootScope, $http, $urlRouter) {
$rootScope.$on('$locationChangeSuccess', function(event) {
event.preventDefault();// prevents the location change
$http({// make a http call to check if user is logged in or not.
url: '/path/to/check/auth',
method: 'post',
data: {}
}).then(function(response){
if(response.data.isUserLoggedIn){//If user is logged in.
$urlRouter.sync();
}else{//user is not logged in
window.location.assign('/login');
}
}, function() {
window.location.assign('/login');
});
});
$urlRouter.listen();
}]);

AngularJs - Create public pages and restric pages

I need to create some pages with restrictions and my code works fine but when I try to access pages that have an ID none works and automatically redirects me to the login. Can anyone tell me why?
function run($rootScope, $http, $location, $localStorage) {
// keep user logged in after page refresh
if ($localStorage.currentUser) {
$http.defaults.headers.common.Authorization = 'Bearer ' + $localStorage.currentUser;
}
// redirect to login page if not logged in and trying to access a restricted page
$rootScope.$on('$locationChangeStart', function (event, next, current, Auth) {
var publicPages = ['/login','/','/job','/job/:jobId'];
var restrictedPage = publicPages.indexOf($location.path()) === -1;
if (restrictedPage && !$localStorage.currentUser) {
$location.path('/login');
}
});
}
My config
.when("/job" , {
templateUrl: "app/components/job/views/job.html",
controller: "job"
})
.when("/job/:jobId" , {
templateUrl: "app/components/job/views/jobdetail.html",
controller: "job_detail"
})
I think your verification for public pages is wrong.
The path /job/:jobId is only a route.
Calling $location.path() returns the current path where the parameter is substituted and so returns /job/1 which is not in your publicPages array.
I would also recommend using ui router. It makes your life a lot easier and there are a lot tutorials how to use it (e.g. Handling basic route authorization in AngularJS)
If you are using ui.router then you can implement a scalable solution as follows. In this example any state start with app requires authentication. Login to the app using test#gmail.com as the email as password as 123. ui.router hooks does the trick!.
.run(($transitions, $state, $injector) => {
$transitions.onBefore({
to: 'app.**'
}, () => {
const $window = $injector.get('$window');
if (!$window.sessionStorage.getItem('user')) {
return $state.target('login', $state.transition.params());
}
return true
});
});
https://plnkr.co/edit/ZCN2hB34mMEmBJulyaAJ?p=preview

AngularJs Authentication how to avoid flickering

I am building an application with AngularJs and I want to prevent user from accessing application's internal pages if he is not logged in.
I have a separate application for login (loginApp) and for the main application (mainApp). What I have done so far in mainApp in order to support authentication is the following:
mainApp.config(['$routeProvider', function($routeProvider) {
$routeProvider. when('/apage', {
templateUrl: ...,
controller: ....,
resolve: {
load: function($q, AuthService){
var defer = $q.defer();
if(AuthService.notLoggedIn) {
defer.reject('user_not_logged_in');
} else {
defer.resolve();
}
return defer.promise;
}
}
}).run(function($rootScope, $window) {
$rootScope.$on('$routeChangeError', function(event, next, current, rejection) {
if (rejection === 'user_not_logged_in') {
$window.location = '/html/pages/login.html';
}
});
});
}])
My mainApp's html page is consisted of a navbar (which is controlled by controllers defined in navbarControllers module) and a div enclosing ng-view directive (partial pages go there).
My problem is that the code above works fine for the partial pages but not for the navbar. Navbar is loaded normally, its controllers try to make calls to backend but they fail (as user is not authenticated) so alerts popup and then redirects to login page. Why is this happening? How can I prevent navbarControllers module from loading and navbar from showing?
You can use something like this
#if (Request.IsAuthenticated) {
// code for your navbar which required user authentication
}
else {
// navbar for logged out user.
}

Redirect when app is initialized in angularjs

On first page load when app gets initialized I want to redirect the user to login page. I think the relevant part of the code is this
$rootScope.$on("$routeChangeStart", function (event, next, current) {
alert("change location");
$location.path('/login');
});
It is based on https://github.com/fnakstad/angular-client-side-auth/blob/master/app/js/app.js The problem is on page load the alert is triggered but location does not change. I have to click on a navigation item of my app and then the login action will be called and the route changes.
.run(['$rootScope', '$location', '$cookieStore', function ($rootScope,
$location, $cookieStore) {
$location.path('/login');
$rootScope.$on("$routeChangeStart", function (event, next, current) {
$location.path('/login');
});
$rootScope.appInitialized = true;
}]);
This will work however seems redundant. And why is alert triggered but not location change?
Why does the location not changes on full page load? How to fix this?
Full code http://jsfiddle.net/qfSC3/ but fiddle does not work.
Try using the $locationChangeStart event instead
$scope.$on("$locationChangeStart", function(event){
event.preventDefault();
})
Based off this question: AngularJS - Detecting, stalling, and cancelling route changes

AngularJS: How to hide the template content until user is authenticated?

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.

Resources