I have found a perfectly working and advanced Angularfire-Seed (that encompasses Simple Login). This framework uses ngRoute and $routeProvider to route the appropriate view and to make sure that certain pages are only shown when the user has logged in.
Now I want to integrate this with the Ionic Framework, such that I have an Ionic App that uses this Authentication system. However, Ionic uses $stateProvider.
My question then becomes: how do I combine these two? I guess one of the two has to go and be replaced by the other. But how do you do this?
Below are the two projects that I want to combine:
1. Angular-Fire Seed using $routeProvider (routes.js)
"use strict";
angular.module('myApp.routes', ['ngRoute', 'simpleLogin'])
.constant('ROUTES', {
'/home': {
templateUrl: 'partials/home.html',
controller: 'HomeCtrl',
resolve: {
// forces the page to wait for this promise to resolve before controller is loaded
// the controller can then inject `user` as a dependency. This could also be done
// in the controller, but this makes things cleaner (controller doesn't need to worry
// about auth status or timing of displaying its UI components)
user: ['simpleLogin', function(simpleLogin) {
return simpleLogin.getUser();
}]
}
},
'/chat': {
templateUrl: 'partials/chat.html',
controller: 'ChatCtrl'
},
'/login': {
templateUrl: 'partials/login.html',
controller: 'LoginCtrl'
},
'/account': {
templateUrl: 'partials/account.html',
controller: 'AccountCtrl',
// require user to be logged in to view this route
// the whenAuthenticated method below will resolve the current user
// before this controller loads and redirect if necessary
authRequired: true
}
})
/**
* Adds a special `whenAuthenticated` method onto $routeProvider. This special method,
* when called, invokes the requireUser() service (see simpleLogin.js).
*
* The promise either resolves to the authenticated user object and makes it available to
* dependency injection (see AuthCtrl), or rejects the promise if user is not logged in,
* forcing a redirect to the /login page
*/
.config(['$routeProvider', function($routeProvider) {
// credits for this idea: https://groups.google.com/forum/#!msg/angular/dPr9BpIZID0/MgWVluo_Tg8J
// unfortunately, a decorator cannot be use here because they are not applied until after
// the .config calls resolve, so they can't be used during route configuration, so we have
// to hack it directly onto the $routeProvider object
$routeProvider.whenAuthenticated = function(path, route) {
route.resolve = route.resolve || {};
route.resolve.user = ['requireUser', function(requireUser) {
return requireUser();
}];
$routeProvider.when(path, route);
}
}])
// configure views; the authRequired parameter is used for specifying pages
// which should only be available while logged in
.config(['$routeProvider', 'ROUTES', function($routeProvider, ROUTES) {
angular.forEach(ROUTES, function(route, path) {
if( route.authRequired ) {
// adds a {resolve: user: {...}} promise which is rejected if
// the user is not authenticated or fulfills with the user object
// on success (the user object is then available to dependency injection)
$routeProvider.whenAuthenticated(path, route);
}
else {
// all other routes are added normally
$routeProvider.when(path, route);
}
});
// routes which are not in our map are redirected to /home
$routeProvider.otherwise({redirectTo: '/home'});
}])
/**
* Apply some route security. Any route's resolve method can reject the promise with
* { authRequired: true } to force a redirect. This method enforces that and also watches
* for changes in auth status which might require us to navigate away from a path
* that we can no longer view.
*/
.run(['$rootScope', '$location', 'simpleLogin', 'ROUTES', 'loginRedirectPath',
function($rootScope, $location, simpleLogin, ROUTES, loginRedirectPath) {
// watch for login status changes and redirect if appropriate
simpleLogin.watch(check, $rootScope);
// some of our routes may reject resolve promises with the special {authRequired: true} error
// this redirects to the login page whenever that is encountered
$rootScope.$on("$routeChangeError", function(e, next, prev, err) {
if( angular.isObject(err) && err.authRequired ) {
$location.path(loginRedirectPath);
}
});
function check(user) {
// used by the changeEmail functionality so the user
// isn't redirected to the login screen while we switch
// out the accounts (see changeEmail.js)
if( $rootScope.authChangeInProgress ) { return; }
if( !user && authRequired($location.path()) ) {
$location.path(loginRedirectPath);
}
}
function authRequired(path) {
return ROUTES.hasOwnProperty(path) && ROUTES[path].authRequired;
}
}
]);
2. Ionic Framework (app.js)
// Ionic Starter App
// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
// 'starter.services' is found in services.js
// 'starter.controllers' is found in controllers.js
angular.module('starter', ['ionic', 'starter.controllers', 'starter.services', 'ngCordova', 'firebase'])
.run(function($ionicPlatform) {
$ionicPlatform.ready(function() {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if (window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
}
if (window.StatusBar) {
// org.apache.cordova.statusbar required
StatusBar.styleDefault();
}
});
})
.config(function($stateProvider, $urlRouterProvider) {
// Ionic uses AngularUI Router which uses the concept of states
// Learn more here: https://github.com/angular-ui/ui-router
// Set up the various states which the app can be in.
// Each state's controller can be found in controllers.js
$stateProvider
// setup an abstract state for the tabs directive
.state('tab', {
url: "/tab",
abstract: true,
templateUrl: "templates/tabs.html"
})
// Each tab has its own nav history stack:
.state('tab.chats', {
url: '/chats',
views: {
'tab-chats': {
templateUrl: 'templates/tab-chats.html',
controller: 'ChatsCtrl'
}
}
})
.state('tab.account', {
url: '/account',
views: {
'tab-account': {
templateUrl: 'templates/tab-account.html',
controller: 'AccountCtrl'
}
}
})
.state('tab.login', {
url: '/login',
views: {
'tab-login': {
templateUrl: 'templates/tab-login.html',
controller: 'LoginCtrl'
}
}
});
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/tab/dash');
})
Update (16/01/2015, 10.46)
I have tried the following (replacing routeProvider by urlRouterProvider), it didnt work (nothing is showing up)
index.html, included:
<ion-nav-view></ion-nav-view>
routes.js
"use strict";
angular.module('myApp.routes', ['ngRoute', 'simpleLogin'])
.constant('ROUTES', {
'/home': {
templateUrl: 'templates/home.html',
controller: 'HomeCtrl',
resolve: {
// forces the page to wait for this promise to resolve before controller is loaded
// the controller can then inject `user` as a dependency. This could also be done
// in the controller, but this makes things cleaner (controller doesn't need to worry
// about auth status or timing of displaying its UI components)
user: ['simpleLogin', function(simpleLogin) {
return simpleLogin.getUser();
}]
},
authRequired: true
},
'/chat': {
templateUrl: 'templates/chat.html',
controller: 'ChatCtrl',
authRequired: true
},
'/camera': {
templateUrl: 'templates/camera.html',
controller: 'CameraCtrl',
authRequired: true
},
'/login': {
templateUrl: 'templates/login.html',
controller: 'LoginCtrl'
},
'/account': {
templateUrl: 'templates/account.html',
controller: 'AccountCtrl',
// require user to be logged in to view this route
// the whenAuthenticated method below will resolve the current user
// before this controller loads and redirect if necessary
authRequired: true
}
})
/**
* Adds a special `whenAuthenticated` method onto $routeProvider. This special method,
* when called, invokes the requireUser() service (see simpleLogin.js).
*
* The promise either resolves to the authenticated user object and makes it available to
* dependency injection (see AuthCtrl), or rejects the promise if user is not logged in,
* forcing a redirect to the /login page
*/
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
// credits for this idea: https://groups.google.com/forum/#!msg/angular/dPr9BpIZID0/MgWVluo_Tg8J
// unfortunately, a decorator cannot be use here because they are not applied until after
// the .config calls resolve, so they can't be used during route configuration, so we have
// to hack it directly onto the $routeProvider object
$urlRouterProvider.whenAuthenticated = function(path, route) {
route.resolve = route.resolve || {};
route.resolve.user = ['requireUser', function(requireUser) {
return requireUser();
}];
$urlRouterProvider.when(path, route);
}
}])
// configure views; the authRequired parameter is used for specifying pages
// which should only be available while logged in
.config(['$stateProvider', '$urlRouterProvider', 'ROUTES', function($stateProvider, $urlRouterProvider, ROUTES) {
angular.forEach(ROUTES, function(route, path) {
if( route.authRequired ) {
// adds a {resolve: user: {...}} promise which is rejected if
// the user is not authenticated or fulfills with the user object
// on success (the user object is then available to dependency injection)
$urlRouterProvider.whenAuthenticated(path, route);
}
else {
// all other routes are added normally
$urlRouterProvider.when(path, route);
}
});
// routes which are not in our map are redirected to /home
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/tab/dash');
}])
/**
* Apply some route security. Any route's resolve method can reject the promise with
* { authRequired: true } to force a redirect. This method enforces that and also watches
* for changes in auth status which might require us to navigate away from a path
* that we can no longer view.
*/
.run(['$rootScope', '$location', 'simpleLogin', 'ROUTES', 'loginRedirectPath',
function($rootScope, $location, simpleLogin, ROUTES, loginRedirectPath) {
// watch for login status changes and redirect if appropriate
simpleLogin.watch(check, $rootScope);
// some of our routes may reject resolve promises with the special {authRequired: true} error
// this redirects to the login page whenever that is encountered
$rootScope.$on("$stateChangeError", function(e, next, prev, err) {
if( angular.isObject(err) && err.authRequired ) {
$location.path(loginRedirectPath);
}
});
function check(user) {
// used by the changeEmail functionality so the user
// isn't redirected to the login screen while we switch
// out the accounts (see changeEmail.js)
if( $rootScope.authChangeInProgress ) { return; }
if( !user && authRequired($location.path()) ) {
$location.path(loginRedirectPath);
}
}
function authRequired(path) {
return ROUTES.hasOwnProperty(path) && ROUTES[path].authRequired;
}
}
]);
Related
I want a route to check and see if a Firebase user is signed in before it redirects someone to the /map.html page.
.when('/map', {
templateUrl: 'views/map.html',
controller: 'MapCtrl',
resolve: {
loggedIn: onlyLoggedIn()
}
});
I have tried using resolve (see code above) but I only get errors from the onlyLoggedIn() function that say "user is not defined". User is defined and if I try to pass in user to the function I get an error "Unknown provider: user"
var onlyLoggedIn = function ($location,$q,user) {
var deferred = $q.defer();
console.log("well: "+user);
if (user) {
console.log("user is signed in ");
deferred.resolve();
} else {
deferred.reject();
$location.url('/signup');
}
return deferred.promise;
};
How should I go about checking if a user is signed in with firebase before routing them to the /map page?
Firebase gives me the user variable and in 'other' places in my app it works, so the problem isn't user not being defined, but my onlyLoggedIn function not "getting" it(?)
Security rules in Firebase can prevent the page from data from being viewed without permission. You need a client-side solution to redirect the page. You do in routes.
This is complete code for the Angular Firebase
This is simple code demonstration. I hope that will work for you.
angular.module('myApp.routes', ['ngRoute', 'simpleLogin'])
.constant('ROUTES', {
'/home': {
templateUrl: 'partials/home.html',
controller: 'HomeCtrl',
resolve: {
// forces the page to wait for this promise to resolve before controller is loaded
// the controller can then inject `user` as a dependency. This could also be done
// in the controller, but this makes things cleaner (controller doesn't need to worry
// about auth status or timing of displaying its UI components)
user: ['simpleLogin', function(simpleLogin) {
return simpleLogin.getUser();
}]
}
},
'/chat': {
templateUrl: 'partials/chat.html',
controller: 'ChatCtrl'
},
'/login': {
templateUrl: 'partials/login.html',
controller: 'LoginCtrl'
},
'/account': {
templateUrl: 'partials/account.html',
controller: 'AccountCtrl',
// require user to be logged in to view this route
// the whenAuthenticated method below will resolve the current user
// before this controller loads and redirect if necessary
authRequired: true
}
})
/**
* Adds a special `whenAuthenticated` method onto $routeProvider. This special method,
* when called, invokes the requireUser() service (see simpleLogin.js).
*
* The promise either resolves to the authenticated user object and makes it available to
* dependency injection (see AuthCtrl), or rejects the promise if user is not logged in,
* forcing a redirect to the /login page
*/
.config(['$routeProvider', function($routeProvider) {
// credits for this idea: https://groups.google.com/forum/#!msg/angular/dPr9BpIZID0/MgWVluo_Tg8J
// unfortunately, a decorator cannot be use here because they are not applied until after
// the .config calls resolve, so they can't be used during route configuration, so we have
// to hack it directly onto the $routeProvider object
$routeProvider.whenAuthenticated = function(path, route) {
route.resolve = route.resolve || {};
route.resolve.user = ['requireUser', function(requireUser) {
return requireUser();
}];
$routeProvider.when(path, route);
}
}])
// configure views; the authRequired parameter is used for specifying pages
// which should only be available while logged in
.config(['$routeProvider', 'ROUTES', function($routeProvider, ROUTES) {
angular.forEach(ROUTES, function(route, path) {
if( route.authRequired ) {
// adds a {resolve: user: {...}} promise which is rejected if
// the user is not authenticated or fulfills with the user object
// on success (the user object is then available to dependency injection)
$routeProvider.whenAuthenticated(path, route);
}
else {
// all other routes are added normally
$routeProvider.when(path, route);
}
});
// routes which are not in our map are redirected to /home
$routeProvider.otherwise({redirectTo: '/home'});
}])
/**
* Apply some route security. Any route's resolve method can reject the promise with
* { authRequired: true } to force a redirect. This method enforces that and also watches
* for changes in auth status which might require us to navigate away from a path
* that we can no longer view.
*/
.run(['$rootScope', '$location', 'simpleLogin', 'ROUTES', 'loginRedirectPath',
function($rootScope, $location, simpleLogin, ROUTES, loginRedirectPath) {
// watch for login status changes and redirect if appropriate
simpleLogin.watch(check, $rootScope);
// some of our routes may reject resolve promises with the special {authRequired: true} error
// this redirects to the login page whenever that is encountered
$rootScope.$on("$routeChangeError", function(e, next, prev, err) {
if( angular.isObject(err) && err.authRequired ) {
$location.path(loginRedirectPath);
}
});
function check(user) {
if( !user && authRequired($location.path()) ) {
$location.path(loginRedirectPath);
}
}
function authRequired(path) {
return ROUTES.hasOwnProperty(path) && ROUTES[path].authRequired;
}
}
]);
I have the application config as shown below, when i use method > function redirectWhenLoggedOut($q, $injector) i get Injector:modulerr error and when commenting that block of function the application runs fine. Help me if i miss anything in this code of config block. I'm new to angularjs hope you will help me out.
app.config([ '$stateProvider', '$urlRouterProvider','$authProvider', '$controllerProvider', '$httpProvider', '$compileProvider', '$filterProvider', '$provide', '$ocLazyLoadProvider', 'JS_REQUIRES',
function ($stateProvider, $urlRouterProvider, $authProvider, $controllerProvider, $compileProvider, $httpProvider, $filterProvider, $provide, $ocLazyLoadProvider, jsRequires) {
app.controller = $controllerProvider.register;
app.directive = $compileProvider.directive;
app.filter = $filterProvider.register;
app.factory = $provide.factory;
app.service = $provide.service;
app.constant = $provide.constant;
app.value = $provide.value;
$ocLazyLoadProvider.config({
debug: false,
events: true,
modules: jsRequires.modules
});
function redirectWhenLoggedOut($q, $injector) {
return {
responseError: function(rejection) {
// Need to use $injector.get to bring in $state or else we get
// a circular dependency error
var $state = $injector.get('$state');
// Instead of checking for a status code of 400 which might be used
// for other reasons in Laravel, we check for the specific rejection
// reasons to tell us if we need to redirect to the login state
var rejectionReasons = ['token_not_provided', 'token_expired', 'token_absent', 'token_invalid'];
// Loop through each rejection reason and redirect to the login
// state if one is encountered
angular.forEach(rejectionReasons, function(value, key) {
if(rejection.data.error === value) {
// If we get a rejection corresponding to one of the reasons
// in our array, we know we need to authenticate the user so
// we can remove the current user from local storage
localStorage.removeItem('user');
// Send the user to the auth state so they can login
$state.go('login.signin');
}
});
return $q.reject(rejection);
}
}
}
// Setup for the $httpInterceptor
$provide.factory('redirectWhenLoggedOut', redirectWhenLoggedOut);
// Push the new factory onto the $http interceptor array
$httpProvider.interceptors.push('redirectWhenLoggedOut');
$authProvider.loginUrl = 'http://localhost/himalayan-engineering-college/public/api/authenticate';
// APPLICATION ROUTES
// -----------------------------------
// For any unmatched url, redirect to /app/dashboard
$urlRouterProvider.otherwise("/login/signin");
//
// Set up the states
$stateProvider.state('app', {
url: "/app",
templateUrl: "assets/views/app.html",
resolve: loadSequence('modernizr', 'moment', 'angularMoment', 'uiSwitch', 'perfect-scrollbar-plugin', 'perfect_scrollbar', 'toaster', 'ngAside', 'vAccordion', 'sweet-alert', 'chartjs', 'tc.chartjs', 'oitozero.ngSweetAlert','satellizer','AuthController'),
abstract: true
}).state('app.dashboard', {
url: "/dashboard",
templateUrl: "assets/views/dashboard.html",
resolve: loadSequence('satellizer','jquery-sparkline', 'dashboardCtrl','chartsCtrl'),
title: 'Dashboard',
ncyBreadcrumb: {
label: 'Dashboard'
}
})....//more states
}]);
Can you try correcting the order of dependencies in the function? '$httpProvider', '$compileProvider' are interchanged.
i would like to submit an http request to check if the user is logged in each time a route is changed.
is this possible with the latest version of angular ( 1.4.5 ).
my routes are like this:
// configure routes
app.config(['$routeProvider', function($routeProvider){
$routeProvider
// route for the home page
.when('/', {
templateUrl : 'directives/about.html',
controller : 'mainController'
})
// route for the home page
.when('/login', {
templateUrl : 'directives/login.html',
controller : 'loginContoller'
})
// route for the about page
.when('/about', {
templateUrl : 'directives/about.html',
controller : 'aboutController'
})
// route for the contact page
.when('/contact', {
templateUrl : 'directives/contact.html',
controller : 'contactController'
});
}]);
If you look a the docs you will see what arguments the when() method takes.
The route agument is an object and one property is called resolve.
The resolve property is an map of dependencies that should be resolved.
$routeProvider.when('/', {
templateUrl: 'directives/about.html',
controller: 'mainController',
resolve: {
loginCheck: function (myLoginCheckService) {
return myLoginCheckService();//could return a $q.promise object.
}
}
});
resolve - An optional map of dependencies which should be injected into the controller. If any of these dependencies are promises, the router will wait for them all to be resolved or one to be rejected before the controller is instantiated. If all the promises are resolved successfully, the values of the resolved promises are injected and $routeChangeSuccess event is fired. If any of the promises are rejected the $routeChangeError event is fired.
AngularJS Docs
Look at the docs for more information.
create a helper method
function auth(configs){
// write your auth code here
return configs;
}
At the router would be like this.
.when('/', auth({
templateUrl : 'directives/about.html',
controller : 'mainController'
}))
Can do it by adding routeChangeStart inside run block of Angularjs
app.run(function($rootScope, $location) {
$rootScope.$on( "$routeChangeStart", function(event, next, current) {
if ($rootScope.loggedInUser == null) {
// no logged user, redirect to /login
if ( next.templateUrl === "partials/login.html") {
} else {
$location.path("/login");
}
}
});
});
Context
Users can register with a unique URL slug that identifies their page, e.g. 'http://example.com/slug'.
Current State
In my Express.js file, I successfully check my database to see if the slug exists on a user, then redirect the user from 'http://example.com/slug' to 'http://example.com/#!/slug' to take advantage of Angular's routing.
With Angular, however, I can't use $http or $location services in my router file (since it's taking place inside module.config...see this Stack Overflow explanation for more details).
Desire
Basically what I want to do is route the user to a 'default' view when a valid slug is found, or home if it's not. Any suggestions would be much appreciated.
For reference, my module.config code can be found here (note that the 'default' state I want to use is 'search'):
core.client.routes.js
'use strict';
// Setting up route
angular.module('core').config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
// Redirect to home when route not found.
$urlRouterProvider.otherwise('/');
// Home state routing
$stateProvider.
state('home', {
url: '/',
templateUrl: 'modules/core/views/home.client.view.html'
}).
state('search', {
url: '/search',
templateUrl: 'modules/core/views/search.client.view.html'
});
}
]);
What I would like to do, is something like this...
'use strict';
// Setting up route
angular.module('core').config(['$stateProvider', '$urlRouterProvider', '$http', '$location',
function($stateProvider, $urlRouterProvider, $http, $location) {
// Get current slug, assign to json.
var slug = $location.path();
var data = {
link: slug
};
// Check db for slug
$http.post('/my/post/route', data).success( function(response) {
// Found slug in db
}).error( function(response) {
// Route to home
$location.path('/');
});
// Home state routing
$stateProvider.
state('home', {
url: '/',
templateUrl: 'modules/core/views/home.client.view.html'
}).
state('search', {
// Set URL to slug
url: '/' + slug,
templateUrl: 'modules/core/views/search.client.view.html'
});
}
]);
To directly answer your question, what you want to do is use the routes "resolve" to check for the dependency and redirect to the appropriate view:
angular.module('app', ['ui.router','ngMockE2E'])
.run(function ($httpBackend) {
$httpBackend.whenGET(/api\/slugs\/.*/).respond(function (method, url) {
return url.match(/good$/) ? [200,{name: 'john doe'}] : [404,''];
});
})
.config(function ($stateProvider) {
$stateProvider
.state(
'search',
{
url: '/search?terms=:slug',
template: '<h1>Search: {{vm.terms}}</h1>',
controllerAs: 'vm',
controller: function ($stateParams) {
this.terms = $stateParams.slug;
}
}
)
.state(
'slug',
{
url: '/:slug',
template: '<h1>Slug: {{vm.user.name}}</h1>',
controllerAs: 'vm',
controller: function (user) {
this.user = user
},
resolve: {
user: function ($q, $http, $stateParams, $state) {
var defer = $q.defer();
$http.get('http://somewhere.com/api/slugs/' + $stateParams.slug)
.success(function (user) {
defer.resolve(user);
})
.error(function () {
defer.reject();
$state.go('search', {slug: $stateParams.slug});
});
return defer.promise;
}
}
}
);
});
<div ng-app="app">
<script data-require="angular.js#*" data-semver="1.3.6" src="https://code.angularjs.org/1.3.6/angular.js"></script>
<script data-require="ui-router#*" data-semver="0.2.13" src="//rawgit.com/angular-ui/ui-router/0.2.13/release/angular-ui-router.js"></script>
<script data-require="angular-mocks#*" data-semver="1.3.5" src="https://code.angularjs.org/1.3.5/angular-mocks.js"></script>
<a ui-sref="slug({slug: 'good'})">Matched Route</a>
<a ui-sref="slug({slug: 'bad'})">Redirect Route</a>
<div ui-view></div>
</div>
But, there are a few things you may want to revisit in your example:
Is there a need to perform this check client side if you are already validating and redirecting server side via express?
You seem to be overloading the / route a bit, if home fails, it redirects to itself
You are grabbing slug from $location on app init, not when the view is routed to which could be post init, you need to grab it when ever you are routing to the view
You may want to consider using a GET request to fetch/read data for this request rather than using a POST which is intended generally for write operations (but thats a different story)
I'm trying to redirect users based on authentication so within the resolve of each route state I've placed my service for checking for authentication so in this case login and dashboard.
.state('login', {
url: "/login",
abstract: true,
templateUrl: '/app/login/login.html'
})
// Default login state
.state('login.index', {
url: "",
templateUrl: "/app/login/views/login.html",
controller: 'LoginController',
controllerAs: 'loginCtrl',
resolve: {
UserAuth: session
}
})
.state('dashboard', {
url: "/dashboard",
abstract: true,
templateUrl: '/app/dashboard/dashboard.html',
resolve: {
UserAuth: session
}
})
// Default dashboard state
.state('dashboard.index', {
url: "",
templateUrl: '/app/dashboard/views/page1.html',
controller: 'Page1Controller',
controllerAs: 'page1Ctrl',
resolve: {
UserAuth: session
}
})
// with multiple states like the child route above...
Within my .config for routing I also set up session for use above, which on promise success or existence of a session $state.go to dashboard, else on promise failure $state.go to login.
.config(function($stateProvider, $urlRouterProvider) {
var session = ['$q', '$location', '$state', 'SessionService',
function( $q, $location, $state, SessionService ) {
return SessionService.session()
.then(function( session ) {
// Check location path as $state is not resolved yet
var location = $location.path();
/**
* Check user authentication to dashboard and handle
* state change if session already exists
*/
if( location.indexOf('login') === 1 ) {
// Redirect to default dashboard view
$state.go('dashboard.index');
}
}, function( error ) {
// Check location path as $state is not resolved yet
var location = $location.path();
/**
* Check for unauthorized access to dashboard and handle
* state change if not located on login view
*/
if( location.indexOf( 'dashboard' ) === 1 ) {
// Redirect to default login view
$state.go('login.index');
}
// Don't propagate error since it has been handled and it prevents page
// return $q.reject( error );
});
}];
But, it's running through an infinite loop of 403 errors when I let the session time out, which is the correct server response for promise failure. It enters the if statement, and runs $state.go('login.index'), but keeps looping and never replaces the state with login. Can anyone see what I've done wrong? Works in all cases except session time out, then doesn't redirect.
I dropped together some code that I used in a past project that displays how I setup Authentication and interception of 401/403 on Angular side of things.
https://gist.github.com/jfornoff/4637069c398dc2f5b881
Note that especially the authorization of users can not be reliably done in the frontend and always have your backend authenticate and not give out data blindly to some end-point that your frontend should be using ;-) But I guess that's pretty self-explanatory.
Hope I could help you out!
Bye,
Jan