I am following the angularfire tutorial to authenticate users.
Users are able to register, signin and even signout in the app.
When I try to use a resolve to check for $requireSignIn() for some routes(ui-route), it doesn't work.
Also, I want to do a check for user authentication status($onAuthStateChanged()) in my app.js where my modules are loaded. Then if there is a change in authentication, update authentication service( userAuth). I am using ng-show="authData" / ng-hide="authData to change html for logged in elements. But sometimes even after login, some of these elements are still showing as not logged in. I think this has something to do with the authentication update status.
If a user is logged in and the try to visit the login/signup page send them back to home page.
Here is my app.js
angular
.module('myApp', [
'ngAnimate',
'ngAria',
'ngCookies',
'ngResource',
'ui.router',
'ngMeta',
'firebase'
])
.run(["$rootScope", "$state", function($rootScope, $state) {
$rootScope.$on("$stateChangeError", function(event, toState, toParams, fromState, fromParams, error) {
if (error === "AUTH_REQUIRED") {
$state.go("home");
}
});
}])
.config(['$stateProvider', '$urlRouterProvider', '$locationProvider',
function( $stateProvider, $urlRouterProvider, $locationProvider, ngMetaProvider, $location, userAuth) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('/', {
url: '/',
templateUrl: 'views/main.html',
controller: 'MainCtrl',
meta: {
'title': 'Goaf | Your next great destination',
'description': 'This is the description shown in Google search results'
}
})
.state('home', {
url: '/home',
templateUrl: 'views/home.html',
controller: 'HomeCtrl',
meta: {
'title': 'Goaf | Your next great destination',
'description': 'This is the description shown in Google search results'
},
resolve: {
"currentAuth": ["userAuth", function(userAuth) {
return userAuth.$requireSignIn();
}]
}
})
}]);
Here is the controller for the home page where I want only logged in users:
angular.module('myApp')
.controller('HomeCtrl', ["currentAuth", function ($rootScope, $scope, $http, $interval, $location, userAuth, dataservice, currentAuth) {
$scope.authData = userAuth.isLoggedIn();
}]);
And here is my userAuth service file:
angular.module('myApp')
.service('userAuth', ["$firebaseAuth", function($firebaseAuth) {
var firebaseAuthObject = $firebaseAuth();
this.login = function(loginEmail, loginPassword){
return firebaseAuthObject.$signInWithEmailAndPassword(loginEmail, loginPassword);
};
this.isLoggedIn = function(){
return firebaseAuthObject.$getAuth();
};
this.signOutUser = function() {
firebaseAuthObject.$signOut();
console.log('logging out user!');
};
}
]);
Related
i need to add admin user. I read that i need to separate routes in my app.js file. But i can't find example that i need to done this. May be someone can help me to fix this problem ?
(function () {
'use strict';
angular
.module('app', ['ngRoute', 'ngCookies'])
.config(config)
.run(run);
config.$inject = ['$routeProvider', '$locationProvider'];
function config($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
controller: 'HomeController',
templateUrl: 'home/home.view.html',
controllerAs: 'vm'
})
.when('/login', {
controller: 'LoginController',
templateUrl: 'login/login.view.html',
controllerAs: 'vm'
})
.when('/register', {
controller: 'RegisterController',
templateUrl: 'register/register.view.html',
controllerAs: 'vm'
})
.when('/admin', {
controller: 'AdminController',
templateUrl: 'admin/admin.view.html',
controllerAs: 'vm'
})
.otherwise({ redirectTo: '/login' });
}
run.$inject = ['$rootScope', '$location', '$cookies', '$http'];
function run($rootScope, $location, $cookies, $http) {
// keep user logged in after page refresh
$rootScope.globals = $cookies.getObject('globals') || {};
if ($rootScope.globals.currentUser) {
$http.defaults.headers.common['Authorization'] = 'Basic ' + $rootScope.globals.currentUser.authdata;
}
$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(), ['/login', '/register']) === -1;
var loggedIn = $rootScope.globals.currentUser;
if (restrictedPage && !loggedIn) {
$location.path('/login');
}
});
}
})();
Take a look at this gist
Basically what you need is attach some restriction related data to your route and check on page transition if you are authorized and redirect if not.
Dedicated AuthService can contain currentUser and authorization data instead of chaotic data in the run block.
When a user attempts to visit my home page, I want to be able to redirect them to a different state based on query params.
For example, if URL is: http://example.com, then load the home page.
If URL is: http://example.com?channel=1, then don't load the home page and go to some other state right away.
Here's what I have (doesn't work):
$stateProvider
...
.state('default-template.home', {
url: '/?channel&campaign',
views: {
'': {
templateUrl: 'app/pages/home/home.html',
controller: 'HomeCtrl as vm'
}
},
resolve: {
data: ['$rootScope', '$stateParams', '$state', function($rootScope, $stateParams, $state) {
var channel = $stateParams.channel;
// If channel is 1, redirect
if (channel === 1) {
$state.go('default-template.other-state', {channel: channel});
}
}]
}
})
The problem seems to be that while both states get kicked off ($stateChangeStart event gets kicked off), the end result is the user always ends up on the home page.
Any thoughts on how to make this work?
You can use the $location built-in service to achieve this.
Your code must have an additional state for the fake path as below
$stateProvider
...
.state('default-template.fake.home', {
url: '/?channel',
views: {
'': {
templateUrl: 'app/pages/home/home.html',
controller: 'HomeCtrl as vm'
}
},
})
.state('default-template.home', {
url: '/?channel&campaign',
views: {
'': {
templateUrl: 'app/pages/home/home.html',
controller: 'HomeCtrl as vm'
}
},
resolve: {
data: ['$rootScope', '$stateParams', '$state', function($rootScope, $stateParams, $state) {
var channel = $stateParams.channel;
// If channel is 1, redirect
if (channel === 1) {
$state.go('default-template.other-state', {channel: channel});
}
}]
}
})
Your HomeCtrl should use the $location service to access the url as below
angular.controller('HomeCtrl',function($location,$state){
if($location.$$url= '') //check if it is empty
$state.go('default-template.home');
....................................
})
LIVE DEMO
Hi all I having a hard time figuring this out and ran out of ideas. I have this website which I should restrict some urls if the user has no authentication. I reviewed some questions and found something similar to this. But it is not quite what I wanted it to be.
So I have some link which do not require user authentication but can access the url.
Other link which needs both, access and user authentication.
So this is my app.js looks
angular.module('efutures', [
'ngRoute',
'ngCookies',
'ui.bootstrap',
]).config(['$routeProvider', '$httpProvider', function ($routeProvider, $httpProvider) {
$routeProvider.when('/login', {
templateUrl: 'app/pages/login.html',
controller: 'LoginController',
access: {
allowAnonymous: true //no need auth
}
})
.when('/signup', {
templateUrl: 'app/pages/Signup.html',
controller: 'SignupController',
access: {
allowAnonymous: true //no need auth
}
})
.when('/enteremail', {
templateUrl: 'app/pages/reset pages/reenteremail.html',
controller: 'EmailController',
access: {
allowAnonymous: true //no need auth
}
})
.when('/password-reset', {
templateUrl: 'app/pages/reset pages/password.reset.html',
controller: 'ResetPwdController',
access: {
allowAnonymous: false //needs auth
}
})
.when('/dashboard', {
templateUrl: 'app/pages/dashboard.html',
controller: 'DashboardController',
access: {
allowAnonymous: false //needs auth
}
})
.when('/registration', {
templateUrl: 'app/pages/registration1.html',
controller: 'registationController'
access: {
allowAnonymous: false //needs auth
}
});
$routeProvider.otherwise({
redirectTo: '/login'
});
}]).run(run);
run.$inject = ['$rootScope', '$location', '$cookieStore', '$http'];
function run($rootScope, $location, $cookieStore, $http) {
$rootScope.hasauth = localStorage.getItem('hasauth');
$rootScope.username = localStorage.getItem('username');
$rootScope.$on('$routeChangeStart', function (event, next, current) {
//console.log($rootScope.hasauth);
//console.log(next.access.allowAnonymous);
if (next.access.allowAnonymous || $rootScope.hasauth === null) {
$location.path('/login');
}
else {
event.preventDefault();
}
});
}
So as above explains code, I have 3 pages which doesn't need authentication and can be allowed to access the urls. Also after Logged in I should restrict going back to those 3 pages but should access other remaining ones
the authentication is taken by the loacalStorage hasauth which returns true when logged in and null when not.
How do I approach this? Help is greatly appreciated.
After refreshing the page, the state changes back to login. I am using $sessionStorage to store the data and I am able to print them successfully after login, but when I refresh the page, my page should stay on dashboard.html but routes to login state.
angular.module('App', [
'ngAnimate',
'ngCookies',
'ngResource',
'ngSanitize',
'ngAnimate',
'ngTouch',
'ui.bootstrap',
'ui.router',
'toaster',
'ngStorage'
])
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('login', {
url: '/login',
templateUrl: "views/login.html"
})
.state('dashboard', {
url: '/dashboard',
templateUrl: "views/dashboard.html",
required: true
});
$urlRouterProvider.otherwise('/login');
})
.run(["$rootScope", "$state", "$location", "authService", "$cookies", "$sessionStorage", function ($rootscope, $state, $location, authService, $cookies, $sessionStorage) {
$rootscope.$on('$stateChangeStart', function (e, toState, toParams, fromState, fromParams) {
if (toState.required && !$sessionStorage.authuserid) {
alert("state not authenticated");
e.preventDefault();
$state.go('login');
}
});
}]);
Here is my controller:
angular.module('App')
.controller('loginController', ['$scope', '$http', '$timeout', '$location', '$rootScope', 'AUTHEVENTS', 'authService', '$cookies', '$state', 'userManagementFactory', '$localStorage', '$sessionStorage', function ($scope, $http, $timeout, $location, $rootScope, AUTHEVENTS, authService, $cookies, $state, userManagementFactory, $localStorage, $sessionStorage) {
$scope.login = function () {
authService.login(data).then(function (response) {
$rootScope.$broadcast(AUTHEVENTS.loginSuccess);
console.log("response data is: ", response);
$sessionStorage.auth = response;
$sessionStorage.authname = response.data.name;
$sessionStorage.authrole = response.data.roles[0].name;
$sessionStorage.authuserid = response.data.user_id;
$sessionStorage.authprofilepic = response.data.profile_picture;
if ($sessionStorage.authuserid) {
$state.go('dashboard');
} else {
alert('user not authenticated');
}
}, function (error) {
$scope.responseMessage = error.data.error;
$rootScope.$broadcast(AUTHEVENTS.loginFailed);
}
)
}
}])
Html:
<div ng-controller="loginController">
<header class="main-header" ng-include src="'views/header.html'"></header><!--/main top header -->
<div ui-view></div>
</div>
I am not sure what is causing it to change route on page refresh?
StateConfig doesnt seem to accept 'required' field, please refer https://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$stateProvider
Instead you should have
.state('dashboard', {
url: '/dashboard',
templateUrl: "views/dashboard.html",
data: {
required: true
}
});
and should check like this.
if (toState.data && toState.data.required && !$sessionStorage.authuserid) {
Try moving $urlRouterProvider.otherwise('/login'); before
`$stateProvider
.state('login', {
url: '/login',
templateUrl: "views/login.html"
})
.state('dashboard', {
url: '/dashboard',
templateUrl: "views/dashboard.html",
required: true
});`
I cannot get $state.go('dashboard') to work. I get the error:
Failed to instantiate module app.controllers.login due to:
Error: [$injector:nomod] http://errors.angularjs.org/1.2.19/$injector/nomod?p0=app...
When defined routes I get no errors. What I'm I doing wrong?
I have also tried $stateProvider and get the same error.
This is my controller...
App.js
var app = angular.module('dashboardApp', [
"ngRoute",
"ngAnimate",
"ngTouch",
"mobile-angular-ui",
"ui.router",
"app.factories.storage",
"app.controllers.main",
"app.controllers.login",
"angular-loading-bar"
]);
app.config(function ($stateProvider, $urlRouterProvider) {
// For any unmatched url, send to /route1
$urlRouterProvider.otherwise("/");
$stateProvider
.state('login', {
url: "/",
templateUrl: STATIC_URL + "html/company/login.html",
controller: "loginController"
})
.state('dashboard', {
url: "/dashboard",
templateUrl: STATIC_URL + "html/company/dashboard.html"
})
});
Controller:
angular.module('app.controllers.login', [
"app.factories.http",
"ui.router",
])
.controller("loginController", ['$scope', "$location", "httpTokens", "httpFactory", "toaster", "$state",
function ($scope, $location, httpTokens, httpFactory, toaster, $state ) {
$scope.actionLoginCompanyUser = function () {
var post_data = {username: $scope.user.email, password: $scope.user.password};
httpTokens.createAccessTokens(post_data)
.then(function (responce) {
if (responce.status == 200) {
$state.go('dashboard')
}
else {
toaster.pop('error', "Incorrect Credentials", "Incorrect Email/Password");
}
})
}
}]);
You never defined the route.
angular.module('app.controllers.login', ["app.factories.http","ui.router"])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('dashboard', {
url: "/dashboard",
views: {
"view": {
templateUrl: "views/something.html"
}
}
});
This should work!
If you want something like a re-route to the login page, which I assume, you can also add the following in the config:
$urlRouterProvider.otherwise("login");
What this does is, if someone tries to go to a route which doesn't exist it will route you back to login.
NOTE:
If you are using $q or $timeout, try using $location.path('/dashboard'); instead.
More info on that particular behaviour: https://github.com/angular-ui/ui-router/issues/916