Skip to content
This repository has been archived by the owner on Aug 30, 2021. It is now read-only.

Unauthorized client side routing #796

Merged
merged 1 commit into from
Aug 25, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions modules/core/client/app/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
angular.module(ApplicationConfiguration.applicationModuleName, ApplicationConfiguration.applicationModuleVendorDependencies);

// Setting HTML5 Location Mode
angular.module(ApplicationConfiguration.applicationModuleName).config(['$locationProvider',
function ($locationProvider) {
angular.module(ApplicationConfiguration.applicationModuleName).config(['$locationProvider', '$httpProvider',
function ($locationProvider, $httpProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');

$httpProvider.interceptors.push('authInterceptor');
}
]);

angular.module(ApplicationConfiguration.applicationModuleName).run(function ($rootScope, $state, Authentication) {

// Check authentication before changing state
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
if (toState.data && toState.data.roles && toState.data.roles.length > 0) {
Expand All @@ -24,11 +27,11 @@ angular.module(ApplicationConfiguration.applicationModuleName).run(function ($ro

if (!allowed) {
event.preventDefault();
$state.go('authentication.signin', {}, {
notify: false
}).then(function () {
$rootScope.$broadcast('$stateChangeSuccess', 'authentication.signin', {}, toState, toParams);
});
if (Authentication.user !== undefined && typeof Authentication.user === 'object') {
$state.go('forbidden');
} else {
$state.go('authentication.signin');
}
}
}
});
Expand Down
36 changes: 25 additions & 11 deletions modules/core/client/config/core.client.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,30 @@ angular.module('core').config(['$stateProvider', '$urlRouterProvider',

// Home state routing
$stateProvider
.state('home', {
url: '/',
templateUrl: 'modules/core/client/views/home.client.view.html'
})
.state('not-found', {
url: '/not-found',
templateUrl: 'modules/core/client/views/404.client.view.html',
data: {
ignoreState: true
}
});
.state('home', {
url: '/',
templateUrl: 'modules/core/client/views/home.client.view.html'
})
.state('not-found', {
url: '/not-found',
templateUrl: 'modules/core/client/views/404.client.view.html',
data: {
ignoreState: true
}
})
.state('bad-request', {
url: '/bad-request',
templateUrl: 'modules/core/client/views/400.client.view.html',
data: {
ignoreState: true
}
})
.state('forbidden', {
url: '/forbidden',
templateUrl: 'modules/core/client/views/403.client.view.html',
data: {
ignoreState: true
}
});
}
]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use strict';

angular.module('core').factory('authInterceptor', ['$q', '$injector',
function ($q, $injector) {
return {
responseError: function(rejection) {
if (!rejection.config.ignoreAuthModule) {
switch (rejection.status) {
case 401:
$injector.get('$state').transitionTo('authentication.signin');
break;
case 403:
$injector.get('$state').transitionTo('forbidden');
break;
}
}
// otherwise, default behaviour
return $q.reject(rejection);
}
};
}
]);
6 changes: 6 additions & 0 deletions modules/core/client/views/400.client.view.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<h1>Bad Request</h1>
<div class="alert alert-danger" role="alert">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
<span class="sr-only">Error:</span>
You made a bad request
</div>
6 changes: 6 additions & 0 deletions modules/core/client/views/403.client.view.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<h1>Forbidden</h1>
<div class="alert alert-danger" role="alert">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
<span class="sr-only">Error:</span>
You are not authorized to access this resource
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
'use strict';

(function() {
describe('authInterceptor', function() {
//Initialize global variables
var authInterceptor,
$q,
$state,
httpProvider;

// Load the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));

//Load httpProvider
beforeEach(module(function($httpProvider) {
httpProvider = $httpProvider;
}));

beforeEach(inject(function(_authInterceptor_, _$q_, _$state_) {
authInterceptor = _authInterceptor_;
$q = _$q_;
$state = _$state_;
spyOn($q,'reject');
spyOn($state,'transitionTo');
}));

it('Auth Interceptor should be object', function() {
expect( typeof authInterceptor).toEqual('object');
});

it('Auth Interceptor should contain responseError function', function() {
expect( typeof authInterceptor.responseError).toEqual('function');
});

it('httpProvider Interceptor should have authInterceptor', function() {
expect(httpProvider.interceptors).toContain('authInterceptor');
});

describe('Forbidden Interceptor', function() {
it('should redirect to forbidden route', function () {
var response = {status:403,config:{}};
var promise = authInterceptor.responseError(response);
expect($q.reject).toHaveBeenCalled();
expect($state.transitionTo).toHaveBeenCalledWith('forbidden');
});
});

describe('Authorization Interceptor', function() {
it('should redirect to signIn page for unauthorized access', function () {
var response = {status:401,config:{}};
var promise = authInterceptor.responseError(response);
expect($q.reject).toHaveBeenCalled();
expect($state.transitionTo).toHaveBeenCalledWith('authentication.signin');
});
});
});
})();