Angularjs: allow unauthorized access only for one page - angularjs

I am using ui-router. I am trying to authenticate all pages except sign up page.
Here are important parts of code:
In app.js:
$transition.onStart({ to: function(state) {
return state.data != null && state.data.authRequired === true;
}},function(trans){
var AuthService = trans.injector().get('AuthService');
....
});
In routes.js:
$stateProvider.state('signup', {
url: '/signup',
templateUrl:'views/signeup.html',
controller: 'SigneUp',
data: {
authRequired: false
}
});
But I am not allowed to go to signup page unless I am authenticated.

You will need to have a service that does Authorization and stores state of current auth for any given user. From there, in each of your controllers, check for auth status, where required, allow access when not logged in; where not, make a stop gate.
eg:
angular.module('app', [])
.controller('ctrlname', ['$scope', '$location', 'myAuthenticationService', function($scope, $location, myAuthenticationService){
//userId and Password to be bound to partials via ng-model.
if (myAuthenticationService.authorizeUser(userId, password)){
// DO what you have to for an authorized user.
}
else{
//
$location.route('/unauthorized');
}
}]
.service('myAuthenticationService', ['$http', function($http){
var self = this;
//This is just for reference, might need more sophesticated authentication on server side anyways.
self.authorizeUser = function(userId, password){
return $http.get(`url/?userId=${userId}&password=${password}`)
.success(function(response){
//If user is validated,
return true;
})
.error(function(error){
return false;
})
}
return {
authorizeUser: function(userId, password){
return self.authorizeUser(userId, password);
}
}
}]
You could define your routes and add corresponsing controllers in routes.js.

Related

Display username on every webpage after login in Angular

I'm using Satellizer for authentication in my Angular app and have pretty much everything working... except that I can't seem to figure out how to display the username (or email) after successful login in the navbar.
My login controller looks like this
$scope.login = function() {
$auth.login($scope.user).then(function(response) {
$scope.user = JSON.stringify(response.data.user);
localStorage.setItem('user', user);
$scope.user = response.data;
$rootScope.authenticated = true;
$rootScope.currentUser = response.data.user;
// redirect user here after successful login
$state.go('home');
}
}
I have this in my $states (using UI Router) for global access
.run(function ($rootScope, $auth, $state) {
$rootScope.$on('$stateChangeStart', function (event, toState, fromState) {
if (toState.loginRequired && !$auth.isAuthenticated()) {
//if ($auth.isAuthenticated()) {
$rootScope.currentUser = JSON.parse($state, localStorage.currentUser);
//$rootScope.currentUser = JSON.stringify($state, localStorage.currentUser);
$state.go('/login');
event.preventDefault();
};
});
});
And then this in my navbar controller
.controller('NavbarCtrl', function($scope, $rootScope, $window, $auth) {
$scope.isAuthenticated = function() {
return $auth.isAuthenticated();
$scope.user.email = $localStorage.currentUser.email;
}
}
I'm not getting any errors in the console, so I'm not sure exactly where I'm going wrong...?
currentUser is undefined in the localStorage, I thought I was setting that in my login controller code above...?
First, you store the user object after login in localStorage.user, then you read currentUser in NavbarCtrl with
$localStorage.currentUser.email;
You should use the same property user, i.e
$scope.user.email = localStorage.user.email;
But then, why do you need this in local storage?
since you put the currentUser in the $rootScope, you should be able to directly use it in your navbar, e.g.
<span>{{currentUser.email}}</span>

How to handle $rootscope and take user id of logged in user in AngularJS?

I want to find the ID of the logged in user and display it in a page. I am new to angular and I don't have much clue on how to handle a session..
I have an angular app which is connected to backend API (.net core).
I will show the instances where $rootScope is used in the website (login and authorization is already enabled). I need to get an understanding of this to learn the app.
In App.js :
//Run phase
myApp.run(function($rootScope, $state) {
$rootScope.$state = $state; //Get state info in view
//Should below code be using rootScope or localStorage.. Check which one is better and why.
if (window.sessionStorage["userInfo"]) {
$rootScope.userInfo = JSON.parse(window.sessionStorage["userInfo"]);
}
//Check session and redirect to specific page
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){
if(toState && toState.data && toState.data.auth && !window.sessionStorage["userInfo"]){
event.preventDefault();
window.location.href = "#login";
}
if(!toState && !toState.data && !toState.data.auth && window.sessionStorage["userInfo"]){
event.preventDefault();
window.location.href = "#dashboard";
}
});
});
Users.js :
'use strict';
angular.module('users', []);
//Routers
myApp.config(function($stateProvider) {
//Login
$stateProvider.state('login', {
url: "/login",
templateUrl: 'partials/users/login.html',
controller: 'loginController'
});
//Factories
myApp.factory('userServices', ['$http', function($http) {
var factoryDefinitions = {
login: function (loginReq) {
$http.defaults.headers.common['Access-Control-Allow-Origin'] = '*';
return $http.post('http://localhost:1783/api/token?UserName='+loginReq.username+'&password='+loginReq.password).success(function (data) { return data; });
}
}
return factoryDefinitions;
}
]);
//Controllers
myApp.controller('loginController', ['$scope', 'userServices', '$location', '$rootScope', function($scope, userServices, $location, $rootScope) {
$scope.doLogin = function() {
if ($scope.loginForm.$valid) {
userServices.login($scope.login).then(function(result){
$scope.data = result;
if (!result.error) {
window.sessionStorage["userInfo"] = JSON.stringify(result.data);
$rootScope.userInfo = JSON.parse(window.sessionStorage["userInfo"]);
//$localStorage.currentUser = { username: login.username, token: result.data };
//$http.defaults.headers.common.Authorization = 'Token ' + response.token;
$location.path("/dashboard");
}
});
}
};
}]);
I came to know that the information about the user will be available in $rootScope.userInfo. If so, how can I take a value inside it?
Please explain with an example if possible. Thanks in advance.
One:
myApp.controller('loginController', [
'$scope', 'userServices', '$location',
'$rootScope',
function($scope, userServices, $location, $rootScope) {
Inside the controller, $rootScope was injected which makes you have access to the userInfo in that controller.
so if you inject $rootScope into another controller and console.log($rootScope.userInfo) you would see the users data.
myApp.controller('anotherController', ['$scope', '$rootScope', function
($scope, $rootScope){
console.log($rootScope.userInfo) //you'd see the users data from sessionStorage
});
According to this post on quora
$scope is an object that is accessible from current component
e.g Controller, Service only. $rootScope refers to an object
which is accessible from everywhere of the application.
You can think $rootScope as global variable and $scope as local variables.
$rootScope Defn.
In your case, once the user is logged in a key "userInfo" in sessionStorage is created and the same data is copied to $rootScope.userInfo. To check the fields in the userInfo after login try
console.log($rootScope.userInfo);
and print it in the console or open your session storage in your browser debugger tools [for chrome open developer tools>applications>sessionstorage>domainname] to view the values in the "userInfo" key.
Suppose you have
{
uid: "10",
fullname: "John Doe"
}
you can access uid in the script using $rootScope.userInfo.uid or $rootScope.userInfo['uid'].
Just in case you are unable to read the code, here is an explanation
if (window.sessionStorage["userInfo"]) {
$rootScope.userInfo = JSON.parse(window.sessionStorage["userInfo"]);
}
is checking the user is logged in or not.
the factory
myApp.factory('userServices', ['$http', function($http) {
var factoryDefinitions = {
login: function (loginReq) {
$http.defaults.headers.common['Access-Control-Allow-Origin'] = '*';
return $http.post('http://localhost:1783/api/token?UserName='+loginReq.username+'&password='+loginReq.password).success(function (data) { return data; });
}
}
is calling the server to get the userInfo object.
$scope.doLogin = function() {
if ($scope.loginForm.$valid) {
userServices.login($scope.login).then(function(result){
$scope.data = result;
if (!result.error) {
window.sessionStorage["userInfo"] = JSON.stringify(result.data);
$rootScope.userInfo = JSON.parse(window.sessionStorage["userInfo"]);
//$localStorage.currentUser = { username: login.username, token: result.data };
//$http.defaults.headers.common.Authorization = 'Token ' + response.token;
$location.path("/dashboard");
}
});
}
};
$scope.doLogin is calling the above factory and storing the userInfo object.

Angular : Wait for app run to get response

As of this post, I'm trying to figure out if the user is logged in (using a token based authentication).
The scheme is following :
1/ The page loads, app run is called, and authenticated is set to false as default
app.run(function($http, UserService) {
UserService.requestCurrentUser();
$http.defaults.xsrfHeaderName = 'X-CSRFToken';
$http.defaults.xsrfCookieName = 'csrftoken';
});
app.constant('AUTHENTICATED', false);
2/ UserService call for its method requestCurrentUser() in which a http get is sent to the correct url with the token in its header.
If token is correct, this sends back the user (success case, we're authenticated).
If not, I get a permission error (error case, we're not authenticated).
This updates currentUserproperty and AUTHENTICATED constant.
app.factory('UserService', function ($http, $q, $window, AUTHENTICATED) {
var _currentUser = {};
return {
getCurrentUser: function() {
return _currentUser;
},
setCurrentUser: function(user) {
_currentUser = user;
},
requestCurrentUser: function() {
return $http.get('/accounts/api/').then(
function (response) {
_currentUser = response.data;
AUTHENTICATED = true;
},
function (error) {
AUTHENTICATED = false;
}
);
},
};
});
3/ Controller is called and authenticated and currentUser scope values are updated.
app.controller('AuthCtrl', function ($scope, AuthService, UserService, AUTHENTICATED) {
$scope.authenticated = AUTHENTICATED;
$scope.currentUser = UserService.getCurrentUser();
});
Problem is that controller tries to reach the values before requestCurrentUser method (launched in app run) has received a response. So where should I launch requestCurrentUser to get the expected behavior ?
Thanks
What you could do it wrap your user state object in a parent object. For example:
var state = {
_currentUser: {}
};
return {
getUserState: function(){ return state; }
};
Then inside your controller:
$scope.state = UserService.getUserState();
This way, when your user updates (no matter when or how in your service), anything bound to the state will receive the update. So your controller will have access to state._currentUser when it is available.

angularjs ui-router authorization before proceeding

I have a angularjs ui-router situation where:
User must be authorized before hitting any page
If user is authorized and has no route, redirect to their homepage
If user is authorized and has a route, redirect to route
If user is authorized and has no route and no homepage, navigate to default page
If user is not authorized and has route, redirect to login page and upon authorization redirect to that route
Its a tricky situation and I can't seem to nail it just right. My current code does work but... it has to shows the 'login' page for a split second before navigating. This happens because I have to kick off the $stateChangeStart somehow.
var app = angular.module('myapp', ['ui.router']);
// handle default states based on authentication,
// default properties set in user profile, or
// or just redirect to 'apps' page
var authd = false,
defaultDashboard = undefined,
defaultFn = function($injector){
// required to get location since loaded before app
var $location = $injector.get('$location');
// if the user has a default dashboard, navigate to that
if(defaultDashboard){
$location.path('workspace/' + defaultDashboard);
} else if(authd) {
// if the user is auth'd but doesn't have url
$location.path('home');
} else {
// if we aren't auth'd yet
$location.path('login');
}
};
app.config(function ($urlRouterProvider, $locationProvider, $stateProvider) {
$locationProvider.html5Mode(true);
app.stateProvider = $stateProvider;
$urlRouterProvider.otherwise(function($injector){
defaultFn($injector);
});
});
app.run(function ($rootScope, $q, $location, $state, $stateParams, $injector, security) {
var deregister = $rootScope.$on("$stateChangeStart", function () {
// authorize is a AJAX request to pass session token and return profile for user
security.authorize().success(function(d){
// set some local flags for defaultFn
authd = true;
defaultDashboard = d.defaultDashboard;
// de-register the start event after login to prevent further calls
deregister();
// switch to default view after login
if($location.$$url === "/login" ||
$location.$$url === "/"){
defaultFn($injector);
}
}).error(function(){
$location.path('login');
});
});
});
I'm using a inceptor to handle 401s like:
var module = angular.module('security.interceptor', []);
// This http interceptor listens for authentication failures
module.factory('securityInterceptor', function($injector, $location) {
return function(promise) {
// Intercept failed requests
return promise.then(null, function(originalResponse) {
if(originalResponse.status === 401) {
$location.path('/login');
}
return promise;
});
};
});
// We have to add the interceptor to the queue as a string because the
// interceptor depends upon service instances that are not available in the config block.
module.config(function($httpProvider) {
$httpProvider.defaults.withCredentials = true;
$httpProvider.responseInterceptors.push('securityInterceptor');
});
anyone had any similar cases and found a better solution?
Heres my solution I came up with:
app.config(function ($urlRouterProvider, $locationProvider, $stateProvider) {
$locationProvider.html5Mode(true);
// placeholder
$stateProvider.state('welcome', {
url: '/'
});
$urlRouterProvider.otherwise('404');
});
app.run(function ($rootScope, $q, $location, $state, $stateParams, security, $urlRouter) {
var deregister = $rootScope.$on("$stateChangeStart", function (event) {
// stop the change!
event.preventDefault();
security.authorize().success(function(d){
// if we don't have a previous url
if($location.$$url === "/" || $location.$$url === "/login"){
// If user has a preset home
if(d.defaultDashboard){
$location.path('workspace/' + d.defaultDashboard);
} else {
$location.path('welcome');
}
} else {
// if we do, then continue
$urlRouter.sync();
}
}).error(function(){
// redirect to home
$location.path('login');
});
// deregister the listener
deregister();
});
});
Essentially, creating a empty route for an empty route solved my problem. Interesting.

How to get the authenticated user info and use in all controllers and services?

I'm using angularFireAuth and I want to retrieve the logged in user's info and use in
all the controllers or services when the app is initial.
Currently, I used this in every controller but i having some problem.
$scope.$on("angularFireAuth:login", function(evt, user){
console.log(user);
});
The callback will not call if it is not a full page load or return null when app initial.
I need some tips for how can I return the authenticated user's info so I can use when app is initial and in all the controllers and services.
Example
When in controller or services
$scope.auth.user.id will return user's ID
$scope.auth.user.name will return user's name
etc
I would start with a userService for this:
angular.module('EventBaseApp').service('userService', function userService() {
return {
isLogged: false,
username: null
}
});
And write a LoginCtrl controller:
angular.module('EventBaseApp')
.controller('LoginCtrl', function ($scope, userService, angularFireAuth) {
var url = "https://example.firebaseio.com";
angularFireAuth.initialize(url, {scope: $scope, name: "user"});
$scope.login = function() {
angularFireAuth.login("github");
};
$scope.logout = function() {
angularFireAuth.logout();
};
$scope.$on("angularFireAuth:login", function(evt, user) {
userService.username = $scope.user;
userService.isLogged = true;
});
$scope.$on("angularFireAuth:logout", function(evt) {
userService.isLogged = false;
userService.username = null;
});
});
Inject the userService anywhere you want the user.
My app that am currently working on that uses this - https://github.com/manojlds/EventBase/blob/master/app/scripts/controllers/login.js
Based on ideas presented here - http://blog.brunoscopelliti.com/deal-with-users-authentication-in-an-angularjs-web-app
i'm not sure quite what your question is. but if you are looking to authorise once rather than in each controller, you can put the code into the module instead and put it into the $rootScope.
var myapp = angular.module('myapp').run(
function ($rootScope) {
$rootScope.user = null;
$rootScope.$on("angularFireAuth:login", function (evt, user) {
$rootScope.user = user;
});
});

Resources