Reputation: 16761
I'm quite new to Angular so this might be a newbie question.
I'm trying to implement a simple task manager (just an exercise) with Rails as backend and Angular as frontend. So far I followed a tutorial and everything worked fine.
Now I want to globally implement Authentication. That means: When a user is not registered and logged in, she should see a splash page or the login page.
I don't want to do that in every single Angular controller, because DRY. So I figured the UI Router might be a good place. And I have a slight suspicion that maybe $httpProvider.interceptors might be useful.
This is how far I got. I can check if a user is authenticated and prevent the page from loading. But nothing more. How would I go from here? Are there any good tutorials out there I missed?
This question on Stackoverflow goes in a similar direction but doesn't solve my problem since they are not using Devise.
Thanks!
// app.js
var app = angular.module("TaskManager", ['ui.router', 'templates', 'Devise'])
.config([
'$stateProvider',
'$urlRouterProvider',
function($stateProvider, $urlRouterProvider){
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'home/_home.html',
controller: 'MainCtrl',
resolve: {
projectPromise: ['projects', function(projects) {
console.log($rootScope);
return projects.getAll();
}]
}
})
.state('projects', {
url: '/projects/{id}',
templateUrl: 'projects/_projects.html',
controller: 'ProjectsCtrl',
resolve: {
project: ['$stateParams', 'projects', function($stateParams, projects) {
return projects.get($stateParams.id);
}]
}
})
.state('login', {
url: '/login',
templateUrl: 'auth/_login.html',
controller: 'AuthCtrl',
onEnter: ['$state', 'Auth', function($state, Auth) {
Auth.currentUser().then(function() {
$state.go('home');
})
}]
})
.state('register', {
url: '/register',
templateUrl: 'auth/_register.html',
controller: 'AuthCtrl',
onEnter: ['$state', 'Auth', function($state, Auth) {
Auth.currentUser().then(function() {
$state.go('home');
})
}]
});
$urlRouterProvider.otherwise('home');
}
]);
// run blocks
app.run(function($rootScope, Auth) {
// you can inject any instance here
$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams){
if(!Auth.isAuthenticated()) {
// So the magic should probably happen here. But how do I implement this?
// And how do I allow users to access the /login and /register page?
event.preventDefault();
}
})
});
Upvotes: 4
Views: 1531
Reputation: 45164
I wrote an article that basically answers this question (at a high level at least) called How to Set Up Authentication with AngularJS and Ruby on Rails.
If you want to check whether the user is authenticated at any particular route, you can (in Angular's standard router, although I don't know about ui-router) use resolve
. Here are a couple routes from an older project of mine:
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl',
isPublic: true
})
.when('/today', {
templateUrl: 'views/announcements.html',
controller: 'AnnouncementsCtrl',
resolve: {
auth: ['$auth', function($auth) {
return $auth.validateUser();
}]
}
})
The root route is public but /today
requires authentication. Maybe that gives you enough to go on for ui-router as well. Side note: I should really update my article to account for ui-router (or Angular's new router) since I don't think many people use the regular old Angular router.
Edit: I remembered this thing from a different project of mine. This is CoffeeScript. Irrelevant code omitted.
"use strict"
angular.module("fooApp", [
"ngAnimate"
"ngCookies"
"ngResource"
"ngRoute"
"ngSanitize"
"ngTouch"
"ui.router"
"ng-token-auth"
])
.run ($rootScope, $auth, $location) ->
$rootScope.$on "auth:login-success", -> $location.path "/"
$rootScope.$on "auth:logout-success", -> $location.path "/sign-in"
$rootScope.$on "$stateChangeStart", (event, next) ->
$auth.validateUser().then (->
if $location.path() == "/"
$location.path "/file-uploads"
), ->
if !next.isPublic
$location.path "/sign-in"
Hopefully it's kind of self-evident what's going on there. This project DOES use ui-router, as you can tell from the $stateChangeStart
.
Upvotes: 1