using auth header to prevent access to page - javascript

On login action I'm storing inside localstorage username and token for logged user where afterwards I'm creating auth. headers that post request.
Update:
to be more specific on this. I have userService which succ. put and retrieve users data from the localstorage, where I have username, sessionId, and isLogged.
My question is: Now having Auth. header, all info I need about logged user inside localstorage, how can I write an event handler to check if the user is logged in before each route change.
Should I do that on app.js where I init my app and to inject userService? if yes how.
(function () {
"use strict";
var app = angular.module("myApp",
["common.services",
"ui.router",
"ui.mask",
"userService",
"ui.bootstrap"]);
....
How can I now use this stored auth header in order to access/deny
access to specific pages?
Update 2: app.js
(function () {
"use strict";
var app = angular.module("myApp",
["common.services",
"ui.router",
"ui.mask",
"userService",
"ui.bootstrap"]);
app.config(["$stateProvider", "$urlRouterProvider",
function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/");
$stateProvider
.state("index", {
url: "/",
templateUrl: "app/index.html",
})
// Restricted
.state("home", {
url: "/home",
templateUrl: "app/home/home.html",
controller: "HomeController as vm"
})
}]
);
}());

i think that the right approach to your problem is to use resolve property in the route, so the user can't navigate to certain pages if he isn't logged in and once he logged in you can inject the user object to the controller
for example to navigate to home page you must be logged in
.when("/home", {
templateUrl: "homeView.html",
controller: "homeController",
resolve: {
user: function(AuthenticationService){
return AuthenticationService.getUser();
}
}
})
app.controller("homeController", function ($scope, user) {
$scope.user = user;
});
good example: https://www.sitepoint.com/implementing-authentication-angular-applications/

You can achieve this by marking required routes with custom attribute and verifying that token is valid when "location" is changing.
Update Assuming you can verify that user is authenticated by checking isLogged property of userService:
(function () {
"use strict";
var app = angular.module("myApp",
["common.services",
"ui.router",
"ui.mask",
"userService",
"ui.bootstrap"]);
app.config(["$stateProvider", "$urlRouterProvider",
function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/");
$stateProvider
.state("index", {
url: "/",
templateUrl: "app/index.html",
})
// Restricted
.state("home", {
url: "/home",
templateUrl: "app/home/home.html",
controller: "HomeController as vm",
data: {
requiresLogin: true
}
})
}]
).run(['$rootScope', '$state', 'userService', function($rootScope, $state, userService) {
$rootScope.$on('$stateChangeStart', function(e, to) {
if (to.data && to.data.requiresLogin && !userService.isLogged) {
e.preventDefault();
$state.go('index');
}
})
}]);
}());

Related

Angular UI router permissions / access control

I am having a lot of trouble determining how to add permissions / access-control to our Angular app. Right now we have this:
app.config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('default', {
url: '',
templateUrl: 'pages/home/view/home.html',
controller: 'HomeCtrl'
})
.state('home', {
url: '/home',
templateUrl: 'pages/home/view/home.html',
controller: 'HomeCtrl',
permissions: { // ?
only: ['Admin','Moderator']
},
access: { // ?
roles: ['*']
},
resolve: { // ?
authenticate: function($state, $q, $timeout){
},
}
})
}]);
I having trouble determining which methodology to use to create access control to each page.
Right now, the logged in user is stored in an Angular value:
app.value('USER', JSON.parse('{{{user}}}'));
The USER value contains the information about which roles / permissions the user has.
But I cannot inject USER into app.config() callback, it says "unknown provider".
How can I do access-control based of the USER parameters?
the key to perform that is to add your access control on an event $stateChangeStart
For example if you have your routing like that :
.state('termsofuse', {
url: "/terms",
templateUrl: "termOfUse.html",
resolve: {
authorizedRoles: function() {
return [USER_ROLES['su'],
USER_ROLES['user'],
USER_ROLES['admin'],
USER_ROLES['skysu']
]
}
}
})
you may define your access controle like that
.run(
function($rootScope, $q, $location, $window, $timeout) {
$rootScope.$on(
'$stateChangeStart',
function(event, next, current) {
var authorizedRoles = next.resolve.authorizedRoles();
//this function controls if user has necessary roles
if (!isAuthorized(authorizedRoles)) {
event.preventDefault();
// and I broadcast the news $rootScope.$broadcast("AUTH_EVENTS.notAuthenticated");
} else {
$rootScope.$broadcast("AUTH_EVENTS.loginSuccess");
}
})
});
Then you just of to define your event's catcher to manager the desired behaviour (redirect / error message or whatever necessary)
You might want to check out ngAA, I use it alongside ui-router.
This is how I got it to work. I am not sure if it's the best way, but it does work.
You cannot inject services/values in the app.config(), but you can inject services/values into the resolve.authenticate function.
I decided to use the resolve.authenticate methodology.
.state('home', {
url: '/home',
templateUrl: 'pages/home/view/home.html',
controller: 'HomeCtrl',
resolve: {
authenticate: handlePageRequest['home'] // <<<<
}
})
and then we have a handler:
let handlePageRequest = {
'default': function ($q, USER, $state, $timeout, AuthService) {
// this page is always ok to access
return $q.when();
},
'home': function ($q, USER, $state, $timeout, AuthService) {
if(AuthService.isHomePageAccessible(USER)){
return $q.when();
}
else{
$timeout(function () {
$state.go('not-found'); // we can prevent user from accessing home page this way
}, 100);
return $q.reject()
}
},
};

Angularjs routing template is not displayed

I have the following app.js file:
'use strict';
var app = angular.module('app', [
'auth0',
'angular-storage',
'angular-jwt',
'ui.router',
'Environment',
'Api',
'Profile'
]);
app.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('main', {
url: '/main',
templateUrl: 'js/modules/App/views/frontpage.html'
})
.state('login', {
url: '/login',
templateUrl: 'js/modules/User/views/login.html',
controller: 'LoginCtrl'
});
$urlRouterProvider
.otherwise('/main');
}]);
app.config(['authProvider', '$httpProvider', '$locationProvider', 'jwtInterceptorProvider',
function myAppConfig(authProvider, $httpProvider, $locationProvider, jwtInterceptorProvider) {
authProvider.init({
domain: 'marcrasmussen.eu.auth0.com',
clientID: 'hphpe4JiceMW8FSA02CN7yOYl5fUaULe',
loginUrl: '/login'
});
authProvider.on('loginSuccess', ['$location', 'profilePromise', 'idToken', 'store',
function ($location, profilePromise, idToken, store) {
console.log("Login Success");
profilePromise.then(function (profile) {
store.set('profile', profile);
store.set('token', idToken);
});
$location.path('/');
}]);
//Called when login fails
authProvider.on('loginFailure', function () {
alert("Error");
});
//Angular HTTP Interceptor function
jwtInterceptorProvider.tokenGetter = ['store', function (store) {
return store.get('token');
}];
//Push interceptor function to $httpProvider's interceptors
$httpProvider.interceptors.push('jwtInterceptor');
}]);
app.run(['auth', function (auth) {
// This hooks all auth events to check everything as soon as the app starts
auth.hookEvents();
}]);
And i have the following profile.js file:
angular.module('Profile', [])
.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('profile', {
abstract: true,
url: '/profile'
})
.state('profile.index', {
url: '/index',
templateUrl: 'js/modules/Profile/views/viewProfile.html'
})
}]);
in my index.html the files are listed as such:
<script src="js/modules/Profile/lib/profile.js"></script>
<script src="js/modules/App/lib/app.js"></script>
<script src="js/modules/App/directives/login/login.js"></script>
And lastly ofcourse i have my view port:
<div class="main" ui-view>
</div>
As you can tell my application starts on the route /main this works perfectly fine and frontpage.html is being rendered with all the html inside that file.
However when i go to profile.index or /profile/index no error is displayed in the console and no html within the template file js/modules/Profile/views/viewProfile.html is displayed.
Can anyone tell me why this is happening? what am i doing wrong?
I think the issue may be your abstract state. You are not defining a template or templateUrl for this state. Also note that the template for your abstract state must include a ui-view directive in order for its children to populate.
https://github.com/angular-ui/ui-router/wiki/nested-states-%26-nested-views#abstract-state-usage-examples
You may need to do something along the lines of:
.state('profile', {
abstract: true,
url: '/profile',
template: '<ui-view />
})

Implementing secure pages and $rootScope is not defined

Inside my angularjs app. I have userService which has method for determination if user is loggedIn or not. userService.user.loggedIn()
now I want to use that service in order to implement secure pages, where I will redirect user upon this userService.user.loggedIn() statement.
my app.js looks like this
(function () {
"use strict";
var app = angular.module("myApp",
["common.services",
"$rootScope",
"ui.router",
"ui.mask",
"userService",
"ui.bootstrap"]);
app.config(["$stateProvider", "$urlRouterProvider",
function ($stateProvider, $urlRouterProvider, $rootScope) {
$urlRouterProvider.otherwise("/");
$stateProvider
.state("index", {
url: "/",
templateUrl: "app/index.html",
})
// Home page /* SECURED */
.state("home", {
url: "/home",
templateUrl: "app/home/home.html",
controller: "HomeController as vm",
data: {
requiresLogin: true
}
})
// Login
.state("login", {
url: "/login",
templateUrl: "app/login/login.html",
controller: "LoginController as vm"
})
}]
);
$rootScope.$on('$stateChangeStart', function (e, to, userService) {
if (to.data && to.data.requiresLogin) {
if (!userService.user.loggedIn()) {
//token not found/not valid
e.preventDefault();
$location.path('/login');
}
}
});
}());
Inside console I'm getting
ReferenceError: $rootScope is not defined
$rootScope.$on('$stateChangeStart', function (e, to, appUserService,
$rootScope)...
It's not in the array of injectable:
Try this:
app.config(["$stateProvider", "$urlRouterProvider", "$rootScope",
function ($stateProvider, $urlRouterProvider, $rootScope) {
You can only place providers in config. So place your $rootScope.$on function in app controller.

securing access to url and rootScope undefined

(function () {
"use strict";
var app = angular.module("myApp",
["common.services",
"$rootScope",
"ui.router",
"ui.mask",
"userService",
"ui.bootstrap"]);
app.config(["$stateProvider", "$urlRouterProvider","$rootScope",
function ($stateProvider, $urlRouterProvider, $rootScope) {
$urlRouterProvider.otherwise("/");
$stateProvider
.state("index", {
url: "/",
templateUrl: "app/index.html",
})
// Home page /* SECURED */
.state("home", {
url: "/home",
templateUrl: "app/home/home.html",
controller: "HomeController as vm",
data: {
requiresLogin: true
}
})
// Login
.state("login", {
url: "/login",
templateUrl: "app/login/login.html",
controller: "LoginController as vm"
})
}]
);
$rootScope.$on('$stateChangeStart', function (e, to, userService) {
if (to.data && to.data.requiresLogin) {
if (!userService.user.loggedIn()) {
//token not found/not valid
e.preventDefault();
$location.path('/login');
}
}
});
}());
You didn't post what the problem is, but I assume it is that nothing works. If so here is obvious problem with your code: you are trying use $rootScope as module dependency to application module.
Correct module definition must be:
angular.module("myApp", [
"common.services",
"ui.router",
"ui.mask",
"userService",
"ui.bootstrap"
])
I removed "$rootScope" from the list.
UPD. Closer look revealed another problem. You can't inject $rootScope into config block. Move it to the run:
app
.config([...])
.run(['$rootScope', function($rootScope) {
$rootScope.$on(...);
}];
you cant inject services (rootScope is service) in config only provides
but you can do it in app.run
Here's the calling order:
app.config() //only provides can be injected
app.run()
directive's compile functions (if they are found in the dom)
app.controller()
directive's link functions (again, if found)
app.run(["$stateProvider","$rootScope","userService",
function($stateProvider,$rootScope,userService){
$rootScope.$on('$stateChangeStart', function (e, toState, toParams, fromState, fromParams) {
if (toState.data && toState.data.requiresLogin) {
if (!userService.user.loggedIn()) {
//token not found/not valid
e.preventDefault();
$location.path('/login');
}
}
});
}]);

Factory and Resource Makes Angular UI Router not Work

I've been following this tutorial https://www.youtube.com/watch?v=X_NZr_-RaLw and in my clientapp.js, when I insert
.factory('UserService', function($resource) {
return $resource('https://troop.tech/api/users/:user', {user: '#user'});
});
Into my code, all the angular UI routing just stops working.
Context:
var myApp = angular.module('myApp', ['ui.router','ngRouter'])
myApp.factory('UserService', function($resource) {
return $resource('https://troop.tech/api/users/:user', {user: '#user'});
});
myApp.config(function($stateProvider, $urlRouterProvider, $httpProvider) {
$urlRouterProvider.otherwise('/dashboard');
$stateProvider
// HOME STATES AND NESTED VIEWS ========================================
.state('home', {
url: '/home',
templateUrl: 'partial-home.html'
})
.state('dashboard', {
url: '/dashboard',
templateUrl: 'partial-dashboard.html'
})
.state('about', {
url: '/about',
templateUrl: 'partial-about.html'
})
.state('register', {
url: '/register',
templateUrl: 'partial-register.html'
});
$httpProvider.interceptors.push('authInterceptor');
});
myApp.controller('userController', function ($scope, $http, $window, UserService) {
$scope.users = UserService.query();
$scope.setDataForUser = function(userID) {
};
$scope.addUser = function(){
};
...
In your factroy you use $resource as a parameter so you need inject angular built in resource liberary.
In index.html:
<script src="yourComponentFolder/angular-resource/angular-resource.js"></script>
And add a module ngResource...
var myApp = angular.module('myApp', ['ui.router','ngRouter','ngResource']);
Reference in your Application that yoy follow
And one thing if you use ui-router not necessary to inject ngRouter so if you can discard ngRouter from module.

Categories

Resources