What Im aiming is that I will have different tabs layout for different users
like patient and doctors
in my controller, I store the logged user in $rootScope.currentUser like this
$auth.login(credentials).then(function(data) {
return $http.get(CONSTANTS.LINK+'/authenticate/user');
}, function(data) {
var alertPopup = $ionicPopup.alert({
title: 'Error Logging in',
template: 'Invalid Credentials'
});
alertPopup.then(function(res) {
});
}).then(function(response) {
var user = JSON.stringify(response.data.user);
localStorage.setItem('user', user);
$rootScope.authenticated = true;
$rootScope.currentUser = response.data.user;
$state.go('tabs.home');
});;
Now this is my app.js. Nothing happens. am i Doing it right?
The $rootscope.currentUser is also returning undefined when i try console.log($rootScope.currentUser);
.state('tabs', {
url: '/tab',
templateUrl: function ($rootScope) {
if($rootScope.currentUser.role == 'Patient') {
return 'templates/tabs.html';
} else if ($rootScope.currentUser.role == 'Doctor') {
return 'templates/tabs-doctors.html';
}
},
abstract: true,
})
Since I was storing the user data in local storage when he logs in, I used that data to check the role of the user.
.state('tabs', {
url: '/tab',
templateUrl: function () {
var user = JSON.parse(localStorage.getItem('user'));
role = user.role;
if(role == 'Patient') {
return 'templates/tabs.html';
} else if (role == 'Doctor') {
return 'templates/tabs2.html';
} else {
return 'templates/tabs.html';
}
},
abstract: true,
})
Related
I have a login system...and I'm trying to implement login/logout feature to a website.
This is the fiddle I'm following- FIDDLE
This is my route file:
(function() {
var onlyLoggedIn = function($location, $q, AuthService2) {
var deferred = $q.defer();
if (AuthService2.isLogin()) {
deferred.resolve();
} else {
deferred.reject();
$location.url('/login');
}
return deferred.promise;
};
angular.module('myApp', [
'ngRoute',
'myApp.login',
'myApp.home',
'myApp.logout',
'myApp.notifications'
])
.factory('AuthService2', ["$http", "$location", function($http, $location) {
//var vm = this;
var baseUrl = 'api/';
return {
isLogin: function() {
var token;
if (localStorage['entrp_token']) {
token = JSON.parse(localStorage['entrp_token']);
} else {
token = "";
}
var data = {
token: token
};
$http.post(baseUrl + 'validateUserToken', data).success(function(response) {
if (response.msg == "authorized") {
//console.log(response.msg);
return localStorage.isLogged === "true";
} else {
return localStorage.isLogged === "false";
}
});
}
}
return {
isLogin: isLogin
};
}])
.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/login', {
controller: 'LoginController',
templateUrl: 'app/components/login/loginView.html',
controllerAs: 'vm'
})
.when('/home', {
controller: 'HomeController',
templateUrl: 'app/components/home/homeView.html',
resolve: {
loggedIn: onlyLoggedIn
},
controllerAs: 'vm'
})
.when('/logout', {
controller: 'LogoutController',
templateUrl: 'app/components/login/loginView.html',
resolve: {
loggedIn: onlyLoggedIn
},
controllerAs: 'vm'
})
.when('/notifications', {
controller: 'NotificationsController',
templateUrl: 'app/components/notifications/notificationsView.html',
resolve: {
loggedIn: onlyLoggedIn
},
controllerAs: 'vm'
})
.otherwise({
redirectTo: '/login'
});
}]);
})();
Users will be visiting login page. After authentication, I set a session and a local storage token.
I use resolve to check whether the user is valid or not. I defined a function for that (as you can see it from the code).
Upon login, I'm able to validate the user and set the session and login controller redirects the valid user to home. But the user reaches the route and he stays in login page itself.
My http request is fine. I checked it and it returns correct result. But I think the function returns false and afterthat only the http request is getting executed. because I can see the http request in consoel and it returns positive result, so the user should get navigated but it's not happening because http request is getting delayed or something.
I tried giving an alert message inside this if else,and it always goes to else condition, no matter what.
if (AuthService2.isLogin()) {
deferred.resolve();
} else {
deferred.reject();
$location.url('/login');
}
Why is it so? I'm pretty much new to ANgular. Is this a limitation of angular?
The problem is that there is no return statement in your isLogin function.
Your return statement is inside the $http.post callback NOT isLogin hence isLogin return undefined thus resolved to falsy.
$http.post(baseUrl + 'validateUserToken', data).success(function(response) {
//Notice that you are inside function(response) closure.
if (response.msg == "authorized") {
return localStorage.isLogged === "true";
} else {
return localStorage.isLogged === "false";
}
});
I can suggest you to return $http.post instead, $http.post return a promise object which you can use in such way, below is an brief example on how you can do it.
isLogin: function() {
//Omitted some code
//This method return a promise object
return $http.post(baseUrl + 'validateUserToken', data);
});
AuthService2.isLogin().then(function(res){
if (response.msg == "authorized") {
deferred.resolve();
} else {
deferred.reject();
$location.url('/login');
}
}, errorCallback); //Optional if you want to handle when post request failed
Code is not tested, just to give you the idea.
How do I prevent a state change for a specific "to" state in ui-router (is it using onEnter?) assuming I have this route:
.state('auth.confirm', {
url: '/confirm/:resetToken',
template: '<confirm-page></confirm-page>',
data: { pageTitle: 'Confirm Reset', specialClass: 'gray-bg' }
})
and this service with this promise-based function:
validateResetToken: function(resetToken) {
var self = this;
var deferred = $q.defer();
$http.post(AppConstants.hostRootUrl + '/auth/reset/validate', { resetToken: resetToken })
.then(function(response) {
if(response.data && response.data.success) {
// if we got a 200 return and it indicates success in the response, resolve
self.message = 'Success';
deferred.resolve(self.message);
}
else if (response.data && !response.data.success && response.data.error) {
// if we got a 200 return, but success is falsey and there's an error message, reject with that message
self.message = response.data.error;
deferred.reject(self.message);
}
else {
// error with generic message
self.message = 'Unknown response. Contact administrator.';
deferred.reject(self.message);
}
}, function(errPost) {
if (errPost.data && errPost.data.error) {
self.message = errPost.data.error;
deferred.reject(self.message);
}
else {
self.message = 'Could not connect.';
deferred.reject(self.message);
}
});
return deferred.promise;
},
For posterity (and Googlers) sake, Alon Eitan made me take a second look at my resolve approach, and I realized that my addition of the catch() was causing the rejected promise to not percolate up. This final code works:
.state('auth.confirm', {
url: '/confirm/:resetToken',
template: '<confirm-page></confirm-page>',
data: { pageTitle: 'Confirm Reset', specialClass: 'gray-bg' },
resolve: {
validated: function($q, $stateParams, AuthService, toastr) {
//$log.log('auth.confirm resolve $stateParams',$stateParams);
return AuthService.validateResetToken($stateParams.resetToken).catch(function(validateErr) {
toastr.error(validateErr, 'Blocked', {closeButton: true});
return $q.reject(validateErr);
});
}
}
})
You can create a rule as in https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-create-rules-to-prevent-access-to-a-state
Adapt their example:
app.config(function($stateProvider) {
$stateProvider.state('privatePage', {
data: {
rule: function(token) {
return validateResetToken(token)
}
});
});
app.run(function($rootScope, $state, $stateParams) {
$rootScope.$on('$stateChangeStart', function(e, to) {
if (!angular.isFunction(to.data.rule)) return;
var result = to.data.rule($stateParams.resetToken);
if (result && result.to) {
e.preventDefault();
// Optionally set option.notify to false if you don't want
// to retrigger another $stateChangeStart event
$state.go(result.to, result.params, {notify: false});
}
});
});
I am trying to implement role based authorization in beeman's loopback-angular-admin repo by using this https://github.com/Narzerus/angular-permission
so I am trying to change the users.config.js to like this -
(function () {
'use strict';
angular.module('com.module.users')
.run(function ($rootScope, gettextCatalog, Permission, AppAuth, User) {
$rootScope.addMenu(gettextCatalog.getString('Users'), 'app.users.list', 'fa-user');
Permission.defineRole('anonymous', function (stateParams) {
// If the returned value is *truthy* then the user has the role, otherwise they don't
return !AppAuth.hasOwnProperty('currentUser');
});
Permission.defineRole('student', function (stateParams) {
// If the returned value is *truthy* then the user has the role, otherwise they don't
AppAuth.ensureHasCurrentUser(function () {
//This call also serves to redirect a user to the login screen, via the interceptor in users.auth.js, if they are not authenticated.
console.log(User.getCurrent());
return !!(User.getCurrent().hasOwnProperty('role') && User.getCurrent().role == 'student');
});
}).defineRole('tutor', function (stateParams) {
// If the returned value is *truthy* then the user has the role, otherwise they don't
AppAuth.ensureHasCurrentUser(function () {
//This call also serves to redirect a user to the login screen, via the interceptor in users.auth.js, if they are not authenticated.
console.log(User.getCurrent());
return !!(User.getCurrent().hasOwnProperty('role') && User.getCurrent().role == 'tutor');
});
});
});
})();
So basically I am defining my roles with the help of AppAuth module that has the following code -
(function () {
'use strict';
/*jshint sub:true*/
/*jshint camelcase: false */
angular
.module('com.module.users')
.factory('AppAuth', function ($cookies, User, LoopBackAuth, $http) {
var self = {
login: function (data, cb) {
LoopBackAuth.currentUserId = LoopBackAuth.accessTokenId = null;
$http.post('/api/users/login?include=user', {
email: data.email,
password: data.password
})
.then(function (response) {
if (response.data && response.data.id) {
LoopBackAuth.currentUserId = response.data.userId;
LoopBackAuth.accessTokenId = response.data.id;
}
if (LoopBackAuth.currentUserId === null) {
delete $cookies['accessToken'];
LoopBackAuth.accessTokenId = null;
}
LoopBackAuth.save();
if (LoopBackAuth.currentUserId && response.data && response.data
.user) {
self.currentUser = response.data.user;
cb(self.currentUser);
} else {
cb({});
}
}, function () {
console.log('User.login() err', arguments);
LoopBackAuth.currentUserId = LoopBackAuth.accessTokenId =
null;
LoopBackAuth.save();
cb({});
});
},
logout: function (cb) {
//Destroy the access token.
User.logout({"access_token": LoopBackAuth.accessTokenId}, function () {
//Destory both cookies that get created.
delete $cookies["access_token"];
delete $cookies["accessToken"];
//Perform the Passport Logout
$http.post('/auth/logout');
});
self.currentUser = null;
cb();
},
ensureHasCurrentUser: function (cb) {
if ((!this.currentUser || this.currentUser.id === 'social') && $cookies.accessToken) {
LoopBackAuth.currentUserId = LoopBackAuth.accessTokenId = null;
$http.get('/auth/current')
.then(function (response) {
if (response.data.id) {
LoopBackAuth.currentUserId = response.data.id;
LoopBackAuth.accessTokenId = $cookies.accessToken.substring(
2, 66);
}
if (LoopBackAuth.currentUserId === null) {
delete $cookies['accessToken'];
LoopBackAuth.accessTokenId = null;
}
LoopBackAuth.save();
self.currentUser = response.data;
var profile = self.currentUser && self.currentUser.profiles &&
self.currentUser.profiles.length && self.currentUser.profiles[
0];
if (profile) {
self.currentUser.name = profile.profile.name;
}
cb(self.currentUser);
}, function () {
console.log('User.getCurrent() err', arguments);
LoopBackAuth.currentUserId = LoopBackAuth.accessTokenId =
null;
LoopBackAuth.save();
cb({});
});
} else {
if(self.currentUser){
console.log('Using cached current user.');
}
cb(self.currentUser);
}
}
};
return self;
});
})();
and then in my routes file I am doing -
$stateProvider
.state('router', {
url: '/router',
template: '<div class="lockscreen" style="height: 100%"></div>',
controller: 'RouteCtrl'
})
.state('error', {
url: '/error',
template: '<div class="text-center alert alert-danger" style="margin: 100px">An error occurred.</div>'
})
.state('app', {
abstract: true,
url: '/app',
templateUrl: 'modules/core/views/app.html',
controller: 'MainCtrl',
data: {
permissions: {
only: ['admin', 'student']
}
}
})
.state('app.home', {
url: '',
templateUrl: 'modules/core/views/home.html',
controller: 'HomeCtrl',
data: {
permissions: {
only: ['admin', 'student']
}
}
})
.state('tutor', {
abstract: true,
url: '/tutor',
templateUrl: 'modules/core/views/app.html',
controller: 'MainCtrl',
data: {
permissions: {
only: ['admin', 'tutor']
}
}
})
.state('tutor.home', {
url: '',
templateUrl: 'modules/core/views/home.html',
controller: 'HomeCtrl',
data: {
permissions: {
only: ['admin', 'tutor']
}
}
});
$urlRouterProvider.otherwise('/router');
but now I am getting the following error in the browser console -
Error: undefined role or invalid role validation
at Object.Permission._findMatchingRole (angular-permission.js:170)
at Object.Permission.resolveIfMatch (angular-permission.js:211)
at Object.Permission.authorize (angular-permission.js:239)
at angular-permission.js:45
at Scope.$broadcast (angular-scenario.js:24081)
at Object.transitionTo (angular-ui-router.js:3229)
at Array.<anonymous> (angular-ui-router.js:2346)
at Object.invoke (angular.js:4185)
at handleIfMatch (angular-ui-router.js:1836)
at angular-ui-router.js:1891
so how can I debug this error or implement client side role based authorization in my loopback app
[..] implement client side role based authorization in my loopback app
This doesn't mean anything, loopback is your server application.
Client-side authorization should be prohibited, since clients can be tampered with.
Authorization should take place server-side exclusively. Client-side you should just adapt the content in function of the role. That way if someone tampers with your client code at least its http requests to the API will fail and your data is safe
Below is my code snippet where i'm trying to use uimodal to display the user detail along with additional detail.
I'm failing to bind the response data to uimodal, Kindly help to resolve this.
$scope.selectedUserData = '';
$scope.edituser = function (user) {
usereditService.resp(size.userid, function (response) {
if (response != false) {
console.log(response[0]);//Specific user details object from API
selectedUserData = response[0];
}
else {
console.log('no user found');
}
});
$scope.modalInstance = $uibModal.open({
animation: false,
backdrop: 'static',
templateUrl: '/_views/_editUser.html',
controller: 'userController',
size: size,
resolve: {
selectedData: function () {
return $scope.selectedUserData;
}
},
controller: function($scope, selectedData) {
$scope.editobj = selectedData;
}
});
modalInstance.result.then(function (response) {
$scope.selected = response;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
The data is coming from async response, so can't get that ajax response data as soon as your requested for it.
You need to follow promise pattern in that case, and return the data in promise chain patter from your resolve's selectedData function.
//assuming usereditService.resp is returning promise object
//it it doesn't returning promise object, you need to create it by custom promise using $q
var userDataPromise = usereditService.resp(size.userid).then(function (response) {
if (response != false) {
console.log(response[0]);//Specific user details object from API
selectedUserData = response[0];
return selectedUserData;
}
else {
console.log('no user found');
return 'no user found';
}
}, function(error){
console.log();
return 'no user found';
});
$scope.modalInstance = $uibModal.open({
animation: false,
backdrop: 'static',
templateUrl: '/_views/_editUser.html',
controller: 'userController',
size: size,
resolve: {
selectedData: function () {
//returning response object here as a promise.
return userDataPromise;
}
},
controller: function($scope, selectedData) {
$scope.editobj = selectedData;
}
});
So I'm trying to get local-auth working with passport and angular-ui but I think i've confused myself. I believe local-signup and local-login work because the redirects are working as expected.
I have a small Auth service that I want to inject and use to store the user information. it looks like this:
myApp.factory('Auth', function() {
var user;
return {
setUser: function(aUser) {
user = aUser;
},
isLoggedIn: function() {
return (user) ? user : false;
}
}
});
My routes look like this:
app.post('/login', function(req, res, next) {
passport.authenticate('local-login', function(err, user, info) {
if (err) {
console.log(err);
return next(err);
}
if (!user) {
console.log(user);
var param = 'There was an error with your login';
return res.redirect('/#/login?valid=' + param);
}
req.logIn(user, function(err) {
if (err) {
console.log(err);
return next(err);
}
//console.log(req);
console.log(user);
return res.redirect('/#/news');
});
})(req, res, next);
});
My states look like this:
myApp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/news");
$stateProvider
.state('news', {
url: "/news",
templateUrl: "templates/news.html",
params: {
message: null
}
})
.state('people', {
url: "/people",
templateUrl: "templates/people.html",
resolve: {
authenticate: authenticate
},
})
.state('login', {
url: "/login",
templateUrl: "templates/login.html"
})
.state('signup', {
url: "/signup",
templateUrl: "templates/signup.html"
})
.state('preLogin', {
url: "/preLogin",
templateUrl: "templates/preLogin.html"
});
function authenticate($q, Auth, $state, $timeout) {
if (Auth.isLoggedIn()) {
return $q.when()
} else {
$timeout(function() {
$state.go('login')
})
return $q.reject()
}
}
});
I don't know how or when to store the user information in my Auth service. I assume I need to do this in the loginCtrl but I don't know how to tell when its a successful login besides the URL redirects.
Any help is appreciated.