Angularjs: restrict access to all pages except few - angularjs

I'm using Angularjs with ui-router and JWT(which is a tool for token based authentication) and want to implement authentication.
Say i want to restrict access to all my pages except three: "/home", "/about" and "/login". How can I achieve this effect?

it's working ! enjoy :)
var scotchApp = angular.module('scotchApp', ['ngCookies','ngRoute','ui.bootstrap']);
scotchApp.run(['$rootScope', '$location', 'Auth', function($rootScope, $location, Auth) {
$rootScope.$on('$routeChangeStart', function(event, current) {
$rootScope.pageTitle = current.$$route.title;
if (!Auth.isLoggedIn() && current.$$route.withLogin || Auth.isLoggedIn() && current.$$route.withoutLogin) {
event.preventDefault();
$location.path('/');
}
});
}]);
scotchApp.config(function($routeProvider) {
$routeProvider
// route for the home page
.when('/list', {
templateUrl: 'pages/list.html',
controller: 'mainController',
title: 'User List',
withLogin: true,
})
.when('/register', {
templateUrl: 'pages/register.html',
controller: 'mainController',
title: 'Register',
withoutLogin: true,
});
});

bellow I'll explain for you how to protect access using angularjs Philosophy:
1- we supposed that you have factory named verifyLogin this factory used to verify if the user connect or not (inside this factory function named isAuth)
2 -file config contains the bellow code:
$stateProvider
.state('docApp.doc_components_profiles', {
needLogin: true,
url : '/admin/page1',
views: {
'content#docApp': {
templateUrl: 'app/admin/pages/profiles.html',
controller : 'AdminController as vm'
}
}
});
here you see that we write attribute named needLogin and we affect to this attribute value = true,in order to access to this path (admin pages) the user must be authenticated.
3 -now you can write as bellow to verify the path each time the user navigate from one to another
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams){
if(toState.needLogin){
if(verifyLogin.isAuth== false)
{
console.log("Ypou must connect before you access to this url!!");
$location.path('/login');
}
}
}

Related

AngularJS controller middleware

I have an Angular endpoint like so:
$stateProvider.state("auth.signin", {
url: "/signin",
views: {
"auth-view#auth": {
templateUrl: "views/auth/signin.html",
controller: "SigninController"
}
}
});
I want a before filter (or a middleware) for my SigninController so if the user is already logged in, I want to redirect him to my HomeController.
In pseudo code, I'm looking for something like this:
$stateProvider.state("auth.signin", {
url: "/signin",
views: {
"auth-view#auth": {
templateUrl: "views/auth/signin.html",
controller: "SigninController"
}
},
before: () => {
if (User.loggedIn() === true) {
return $state.go("app.home");
}
}
});
I used similar features on alot of frameworks so I'm pretty certain Angular has something like this too. What's the Angular way of doing it?
Thank you.
Ps: I'm not using Angular 2 yet.
The ui router triggers a $stateChangeStart event, which you can capture:
app.run(["$rootScope", "$state", function($rootScope, $state) {
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams, options) {
if (toState.name === "auth.signin" && userIsLoggedInLogicHere) {
event.preventDefault(); // prevent routing to the state
$state.transitionTo("app.home");
}
// else do nothing, it will just transition to the given state
})
}]);
See this documentation for reference

How to restrict the page from redirect after login/ logout in Angularjs?

I need to restrict the user from redirect and need to login only with authentication.
I tried but I can redirect to login page using back button and again come to same page using forward button. Even I can go to the required page using URL without login.
My code :
config.$inject = ['$routeProvider', '$locationProvider'];
function config($routeProvider, $locationProvider ) {
$routeProvider
.when('/login', {
controller: 'LoginController',
templateUrl: 'view/login.view.html',
controllerAs: 'vm'
})
.when('/profileData', {
controller: 'profileDataController',
templateUrl: 'view/profiledata.view.html',
controllerAs :'vm'
})
.when('/questionBank', {
controller: 'questionbankController',
templateUrl: 'view/questionbank.view.html',
controllerAs: 'vm'
})
.when('/dashboard', {
// controller: 'PersonalInfoController',
templateUrl: 'view/dashboard.view.html',
controllerAs:'vm'
})
.otherwise({ redirectTo: '/login' });
}
run.$inject = ['$rootScope', '$location', '$cookieStore', '$http'];
function run($rootScope, $location, $cookieStore, $http) {
// keep user logged in after page refresh
$rootScope.globals = $cookieStore.get('globals') || {};
if ($rootScope.globals.currentUser) {
$http.defaults.headers.common['Authorization'] = 'Basic ' + $rootScope.globals.currentUser.authdata; // jshint ignore:line
}
$rootScope.$on('$locationChangeStart', function (event, next, current) {
//redirect to login page if not logged in and trying to access a restricted page
var restrictedPage = $.inArray($location.path(), ['/dashboard','/questionBank', '/profileData']) === -1;
/* var a = $location.$$absUrl.split('#')[1];
var patt = new RegExp(a);
var res = patt.test(restrictedPage); */
var loggedIn = $rootScope.globals.currentUser;
if (restrictedPage && !loggedIn) {
$location.path('/login');
}
});
}
use this :based on response from server
.when('/login', {
controller: 'LoginController',
templateUrl: 'view/login.view.html',
resolve:{
logincheck: checklogedin
})
/ resolve function for user....
var checklogedin = function($q ,$http,$location)
{
var deferred =$q.defer();
$http.get('/loggedin').success(function(user){
if (user.staus==true)
{
//goo
deferred.resolve();
}
else
{
deferred.reject();
$location.url('/login');
}
});
return deferred.promise
};
Based on the code that you have provided, I can't tell 100% what is going on in your code. But... you could always try to use the resolve property on each route that you don't want to allow access without authentication. Here is what that would look like for questionBank:
.when('/questionBank', {
controller: 'questionbankController',
templateUrl: 'view/questionbank.view.html',
controllerAs: 'vm',
resolve: {
auth: function(AuthService, $q){
if(AuthService.isAuthenticated()) return $q.resolve();
return $q.reject();
}
}
})
Each property of the resolve object should return a promise, and if that resolves... the route change works. If it rejects... the route change is not allowed. If the promise never resolves, you are screwed, so make sure it resolves or it will never do the route.
This isn't the only way to try what you are saying. It is A way of trying it.
You can also add event listener on your $scope and prevent moving in case of unauthenticated user.
$scope.$on('$locationChangeStart', function (event, next, current) {
if (!is_logged_in) {
event.preventDefault();
}
});
In my code I have two main controllers LoginCtrl and AppCtrl, and all other controllers are nested within AppCtrl. Then in AppCtrl I have this code, which will check for logged user.
if (localStorageService.get('authToken') === null) {
$state.go('login', {locale: CONFIG.defaultLang});
} else if (!userService.isLoggedIn()) {
tokenStorage.setAuthToken(localStorageService.get('authToken'));
userService.setIdentity(JSON.parse(localStorageService.get('user')));
}
As you can see I store auth token from server in local storage. When page loades this code will be executed and if you are not logged in you will be redirected. And because all other application controllers are nested within AppCtrl this code will be executed every time.
For more info about nested controllers try for example this article - https://rclayton.silvrback.com/parent-child-controller-communication

How to skip login page if user is already logged in ionic framework

I am working on an IONIC application where I have checked if user is already logged in and if user is already logged then application should redirect on dashboard. This functionality is working well, but the application first showing login page for couple of seconds and then redirect to the dashboard.
app.js
$rootScope.$on("$locationChangeStart", function (event, next, current) {
var prefs = plugins.appPreferences;
prefs.fetch('iuserid').then(function (value) {
if (value != '') {
$state.go('app.dashboard');
}
});
.config(function ($stateProvider, $urlRouterProvider, $httpProvider) {
$stateProvider
.state('app', {
url: "/app",
abstract: true,
templateUrl: "templates/menu.html",
controller: 'AppCtrl'
})
.state('login', {
url: "/login",
templateUrl: "templates/login.html",
controller: 'LoginCtrl'
})
.state('app.dashboard', {
url: "/dashboard",
views: {
'menuContent': {
templateUrl: "templates/dashboard.html",
controller: 'DashboardCtrl'
}
}
})
;
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/login');
});
});
I don't know where I am making mistake.
Edit: I am able to authenticate and redirect to the dashboard but my problem is the login page displayed for few (up to 2) seconds and then redirect to the dashboard and I am working on IONIC application
Second Edit
I found the problem but don't know the solution. Preference work greatly in $ionicPlatform.ready but do not work in $locationChangeStart. And I need preference in $locationChangeStart because it runs before $ionicPlatformReady. I desperately need the solution.
I do the following:
in the app.js
.state('login', {
url: "/login",
templateUrl : "templates/session/login.html",
controller : 'SessionCtrl'
})
.state('register', {
url: "/register",
templateUrl : "templates/session/register.html",
controller : 'SessionCtrl'
})
.state('app', {
url: "/app",
abstract: true,
templateUrl : "templates/menu.html",
controller : 'AppCtrl',
onEnter: function($state, Auth){
if(!Auth.isLoggedIn()){
$state.go('login');
}
}
})
.state('app.main', {
url: "/main",
views: {
'menuContent': {
templateUrl : "templates/main_menu.html",
controller : "MainMenuCtrl"
}
}
})
$urlRouterProvider.otherwise('/app/main');
Auth is a factory, it stores the auth session in localstorage.
angular.module('auth.services', [])
.factory('Auth', function () {
if (window.localStorage['session']) {
var _user = JSON.parse(window.localStorage['session']);
}
var setUser = function (session) {
_user = session;
window.localStorage['session'] = JSON.stringify(_user);
}
return {
setUser: setUser,
isLoggedIn: function () {
return _user ? true : false;
},
getUser: function () {
return _user;
},
logout: function () {
window.localStorage.removeItem("session");
window.localStorage.removeItem("list_dependents");
_user = null;
}
}
});
I think you should listen to the event $stateChangeStart on the $rootScope, you can listen to this event during runtime, like this:
angular.module("myapp.permission").run($rootScope){
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
var loggedIn = true;
if(loggedIn) {
$state.go('app.dashboard');
}
}
}
Guys try this elegant solution:
if the user is not logged in and login is required it redirect to login.
if the user try to get to login and he already logged in, prevent him from doing it.
mark every path as "requireAuth" and it will work.
place your code in app.js
.run(function ($rootScope, $location, authService) {
$rootScope.$on('$stateChangeStart', function (ev, to, toParams, from, fromParams) {
if (to.requireAuth && !authService.isAuthed()) {
$location.path("/login");
}
else if (to.name == 'login' && authService.isAuthed()) {
ev.preventDefault();
$location.path("/dashboard");
}
});
})
Remove
$urlRouterProvider.otherwise('/loginpage')
at the bottom of routes.js file.
Inside your "run" block and outside of $ionicPlatform.ready you can use this:
//Check if user loggedin and redirect to login page if not
$rootScope.$on('$stateChangeStart', function (event, toState) {
//Check only if you are not in login page
if(toState.name.indexOf('app') !== -1 ) {
// If user is not logged, will redirect to login page, eg:
var prefs = plugins.appPreferences;
prefs.fetch('iuserid').then(function (value) {
if (value != '') {
$state.go('login');
}
});
}
});
After you must change your:
$urlRouterProvider.otherwise('/login');
for this:
$urlRouterProvider.otherwise('/dashboard');
The idea is directly route to dashboard and if is not logged in, will redirect to login page.

UI-Router state changes but URL and template don't

I'm doing some onStateChange authorization like this:
angular
.module('app')
.run(['$rootScope', '$state', 'Auth', function ($rootScope, $state, Auth) {
$rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState, fromParams) {
console.log(toState);
if (!Auth.authorize(toState.data.allow)) {
console.log("Not authorized");
$state.go('app.auth.login', { redirect: toState.name });
}
console.log('Authorized');
});
}]);
Now, when I go to an unauthorized route, it acts as it should, up to a point. The authorization fails and it tries to redirect to app.auth.login. This is shown in the console.logs:
Object {url: "/", templateUrl: "modules/live/index.html", name: "app.live.index", data: Object}
app.routes.js:225 Not authorized
app.routes.js:222 Object {url: "/auth/login?redirect", templateUrl: "modules/auth/login.html", controller: "LoginController", name: "app.auth.login", data: Object}controller: "LoginController"data: Objectname: "app.auth.login"templateUrl: "modules/auth/login.html"url: "/auth/login?redirect"__proto__: Object
app.routes.js:229 Authorized
app.routes.js:229 Authorized
But the URL stays at the original state (the first attempted state), and I don't see the login screen. The LoginController never gets called (there's a console.log at the start that doesn't show.
If I visit /auth/login I see the login screen as intended.
Here's my app.routes.js:
/*****
* Auth
******/
.state('app.auth', {
abstract: true,
url: '',
template: '<div ui-view></div>',
data: {
allow: access.everyone
}
})
.state('app.auth.login', {
url: '/auth/login?redirect',
templateUrl: 'modules/auth/login.html',
controller: 'LoginController'
})
.state('app.auth.logout', {
url: '/auth/logout',
controller: 'LogoutController'
})
/*****
* Live
******/
.state('app.live', {
abstract: true,
url: '/live',
data: {
allow: access.live
}
})
.state('app.live.index', {
url: '/',
templateUrl: 'modules/live/index.html'
});
What can be causing this odd behaviour?
It happens in this cases, that we do forget to solve situation:
user is already (previously) redirected === user is going to $state.go('app.auth.login') ... no need to redirect
And we should not redirect in such case:
$rootScope.$on("$stateChangeStart",
function (event, toState, toParams, fromState, fromParams) {
if (toState.name === 'app.auth.login')
{
// get out of here, we are already redirected
return;
}
And once we do decide to redirect, we should stop current navigation with event.perventDefault();
if (!Auth.authorize(toState.data.allow)) {
// here
event.perventDefault();
$state.go('app.auth.login', { redirect: toState.name });
}
...
See more for example in this $stateChangeStart event continuing after state change or that Q & A with a working plunker

Divert to alternate homepage if user is not logged in using UI-Router & AngularJS

I would like to have two home pages, the first would be for users who have not logged in and the second for users that are logged in.
This is my current set up:
.config(function ($stateProvider, $urlRouterProvider, $locationProvider, $httpProvider) {
$urlRouterProvider
.otherwise('/');
$locationProvider.html5Mode(true);
$httpProvider.interceptors.push('authInterceptor');
})
.factory('authInterceptor', function ($rootScope, $q, $cookieStore, $location) {
return {
// Add authorization token to headers
request: function (config) {
config.headers = config.headers || {};
if ($cookieStore.get('token')) {
config.headers.Authorization = 'Bearer ' + $cookieStore.get('token');
}
return config;
},
// Intercept 401s and redirect you to login
responseError: function(response) {
if(response.status === 401) {
$location.path('/login');
// remove any stale tokens
$cookieStore.remove('token');
return $q.reject(response);
}
else {
return $q.reject(response);
}
}
};
})
.run(function ($rootScope, $location, Auth) {
// Redirect to login if route requires auth and you're not logged in
$rootScope.$on('$stateChangeStart', function (event, next) {
if (next.authenticate && !Auth.isLoggedIn()) {
$location.path('/login');
}
});
});
.config(function ($stateProvider) {
$stateProvider
.state('main', {
url: '/',
templateUrl: 'app/main/main.html',
controller: 'MainCtrl',
title: 'Home',
mainClass: 'home',
headerSearch: true
});
});
How could I reconfigure this so I could do something like the following:
.config(function ($stateProvider) {
$stateProvider
.state('welcome', {
url: '/',
templateUrl: 'app/welcome/welcome.html',
controller: 'WelcomeCtrl',
title: 'Welcome',
mainClass: 'welcome',
isLoggedIn: false
});
$stateProvider
.state('main', {
url: '/',
templateUrl: 'app/main/main.html',
controller: 'MainCtrl',
title: 'Home',
mainClass: 'home',
isLoggedIn: true
});
});
Just wanted to show, how we can manage authentication driven access to states. Based on this answer and its plunker, we can enrich each state (which should be accessible only for authenticated users) with a data setting, explained here: Attach Custom Data to State Objects (cite:)
You can attach custom data to the state object (we recommend using a data property to avoid conflicts)...
So let's have some states with public access:
// SEE no explicit data defined
.state('public',{
url : '/public',
template : '<div>public</div>',
})
// the log-on screen
.state('login',{
url : '/login',
templateUrl : 'tpl.login.html',
controller : 'UserCtrl',
})
...
And some with private access:
// DATA is used - saying I need authentication
.state('some',{
url : '/some',
template : '<div>some</div>',
data : {requiresLogin : true }, // HERE
})
.state('other',{
url : '/other',
template : '<div>other</div>',
data : {requiresLogin : true }, // HERE
})
And this could be hooked on on the state change:
.run(['$rootScope', '$state', 'User', function($rootScope, $state, User)
{
$rootScope.$on('$stateChangeStart'
, function(event, toState, toParams, fromState, fromParams) {
var isAuthenticationRequired = toState.data
&& toState.data.requiresLogin
&& !User.isLoggedIn
;
if(isAuthenticationRequired)
{
event.preventDefault();
$state.go('login');
}
});
}])
See all that in action here
There is similar Q & A were I try to show the concept of redirecting Authenticated and Not Authenticated user:
Angular UI Router: nested states for home to differentiate logged in and logged out
maybe that could help to get some idea, how we can use ui-router, and its event '$stateChangeStart' to hook on our decision manager - and its forced redirecting...
the code should be something like this
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState) { //, fromParams
console.log(toState.name + "," + fromState.name);
if(fromState.name === "") {
if (Auth.isLoggedIn()) {
$state.go('welcome');
event.preventDefault();
} else {
$state.go('home');
event.preventDefault();
} else {
if (toState.authenticate && !Auth.isLoggedIn()) {
$toState.go('login');
event.preventDefault();
}
}
}
so if user entering the application, then if he is logged in take him to welcome else take him to home.
once he is inside, then if he hits some route which needs auth.. then redirect him to login page..
sorry if i did not understood you requirement fully...
.config(function ($stateProvider,$rootScope) {
$stateProvider
.state('welcome', {
url: '/',
templateUrl: 'app/welcome/welcome.html',
controller: 'WelcomeCtrl',
onEnter: function() {
if (userIsLoggedIn()) {
$stateProvider.go('home');
}
});
});
I had problem like this and I solved it like this
.run(function ($rootScope, $location, AuthService) {
// start showing PRELOADER because we doing async call and we dont know when it will be resolved/rej
AuthService.checkLoginStatus().then(
(resp) => {
// fire logged in user event
$rootScope.$broadcast('userLogged',resp);
$location.path(YourHomePageUrl);
},
(err)=> {
// Check that the user is not authorized redirect to login page
$location.path(loginURL);
}
}).finally(
()=> {
// finnaly Set a watch on the $routeChangeStart
/// Hide PRELOADER
$rootScope.$on('$routeChangeStart',
function (evt, next, curr) {
if (!AuthService.isLoggedIn()) {
$location.path(art7.API.loginURL);
}
});
}
)
});
and im not using interceptor for handling 401 not authorized errors, thats my solution

Resources