AngularJS Devise authorization - ruby-on-rails

I'm trying to add authorization functionality to my app, sow for example when I want to go to /admin/posts/create it will redirect me to /login if I'm not already logged in.
My angular module
angular.module('flapperNews', ['ui.router', 'templates', 'ngResource', 'formly', 'formlyBootstrap', 'ngMessages', 'Devise'])
I'm using this service
angular.module('flapperNews')
.factory('authorization', [
'$state',
'Auth',
'$location',
function($state, Auth, $location) {
return {
authorize: function() {
var isAuthenticated = Auth.isAuthenticated();
if (isAuthenticated === false) {
$state.go('login');
}
}
};
}
]);
These are my routes
$stateProvider.state('home', {
url: '/',
controller: 'PostsCtrl',
templateUrl: 'posts/_posts.html'
});
$stateProvider.state('admin', {
abstract: true,
resolve: {
authorize: ['authorization', function(authorization) {
return authorization.authorize();
}]
},
template: '<div ui-view />'
});
$stateProvider.state('postsCreate', {
parent: 'admin',
url: '/admin/posts/create',
controller: 'PostsCtrl as vm',
templateUrl: 'posts/create.html'
});
Through this link I'm trying to access route where I shouldn't be able to get
<a ui-sref="postsCreate" class="btn btn-primary">Create a post</a>
I don't get any errors and I end up in section which I should be able to access.

Related

How to call update_password after request_reset in ng-token-auth and devise-token-auth?

I am using rails api devise-token-auth and Angular Front with ng-token-auth. I am getting problems in the Forgot Password?.
I want that after successful forgot password request, the user is allowed to login and redirected to my update_password path to change password.
The result is user gets login but the redirect url does not go to update_password path.
My redirect url becomes from: http://localhost:9000/#/auth/update_password to http://localhost:9000/?client_id=7gcm9TRnCY0BQh_q83ayPQ&config=default&expiry=&reset_password=true&token=e7Pf34gAC45GPemR6umXwQ&uid=email3%40email.com#/auth/update_password
please note that #/auth/update_password goes to end of link.
My ng-route is like below:
mainApp.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/pages/Home.html',
controller: 'HomeCtrl'
})
.when('/auth/signup', {
templateUrl: 'views/auth/signup.html',
controller: 'authCtrl'
})
.when('/auth/signin', {
templateUrl: 'views/auth/signin.html',
controller: 'authCtrl'
})
.when('/auth/request_reset',{
templateUrl: 'views/auth/requestResetPassword.html',
controller: 'authCtrl'
})
.when('/auth/update_password',{
templateUrl: 'view/auth/updatePassword.html',
controller: 'authCtrl'
})
.otherwise({
redirectTo: '/'
});
});
My ng-token-auth settings are:
mainApp.constant('railsServer', 'http://localhost:3000/api/v1');
mainApp.constant('angServer', 'http://localhost:9000/#');
mainApp.config(function ($authProvider, angServer, railsServer) {
$authProvider.configure({
apiUrl: railsServer,
storage: 'localStorage',
confirmationSuccessUrl: 'http://localhost:9000/#/auth/update_password',
passwordResetSuccessUrl: 'http://localhost:9000/#/auth/update_password'
});
});
My authCtrl is:
var authApp = angular.module('authModule', []);
authApp.controller('authCtrl', ['$scope', '$auth', '$http', '$location', 'railsServer', '$log', function ($scope, $auth, $http, $location, railsServer, $log) {
$scope.go = function (path) {
$location.path(path);
};
var rails_server_path = railsServer;
$scope.userSignUp = function (userSignUpForm) {
$auth.submitRegistration(userSignUpForm)
.then(function (resp) {
$log.info("Welcome " + resp.data.data.email + " !");
})
.catch(function (resp) {
$log.error(resp.data.errors.full_messages[0]);
});
};
$scope.userSignIn = function (userSignInForm) {
$auth.submitLogin(userSignInForm)
.then(function (resp) {
$log.info("Welcome " + resp.email + " !");
$location.path('/#/')
})
.catch(function (resp) {
$log.error(resp.errors[0]);
});
};
$scope.userRequestReset = function(userRequestResetForm){
$auth.requestPasswordReset(userRequestResetForm)
.then(function(resp){
$log.info(resp);
})
.catch(function(resp){
$log.error(resp);
});
};
$scope.userUpdatePassword = function(userUpdatePasswordForm){
$auth.updatePassword(userUpdatePasswordForm)
.then(function(resp){
$log.info(resp);
})
.catch(function(resp){
$log.error(resp.data.errors[0]);
});
};
}]);
My devise-token-auth setting are default settings.

Devise Angular Authentication

I am trying to authenticate into devise via angular. On loading localhost, I see a POST 401 error. This issue seems to be with some devise setting, as my X-CSRF-TOKEN is being passed, but my POST requests aren't accepted.
I am able to register a user successfully, and immediately log in to that user (register also logs user in). I am then able to log out.
Here is the issue: I cannot log in to that user again.
My angular app is inside rails, so the two aren't disconnected.
What do I do? Here are relevant files:
app.js
var myApp = angular.module('myApp', ['templates','ui.router','ui.bootstrap', 'Devise']);
myApp.config([
'$httpProvider', function($httpProvider) {
return $httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content');
}
]);
myApp.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
/**
* Routes and States
*/
$stateProvider
.state('home', {
url: '/',
templateUrl: 'home.html',
controller: 'HomeCtrl'
})
.state('login', {
url: '/login',
templateUrl: 'login.html',
controller: 'AuthCtrl',
onEnter: ['$state', 'Auth', function($state, Auth) {
Auth.currentUser().then(function (){
$state.go('home');
})
}]
})
.state('register', {
url: '/register',
templateUrl: 'register.html',
controller: 'AuthCtrl',
onEnter: ['$state', 'Auth', function($state, Auth) {
Auth.currentUser().then(function (){
$state.go('home');
})
}]
});
// default fall back route
$urlRouterProvider.otherwise('/');
// enable HTML5 Mode for SEO
//$locationProvider.html5Mode(true);
});
myApp.run(function() {
return console.log('angular app running');
});
authCtrl.js
angular.module('myApp')
.controller('AuthCtrl', [
'$scope',
'$state',
'Auth',
function($scope, $state, Auth){
$scope.login = function() {
Auth.login($scope.user).then(function(){
$state.go('home');
});
};
$scope.register = function() {
Auth.register($scope.user).then(function(){
$state.go('home');
});
};
}]);
navCtrl.js
angular.module('myApp')
.controller('NavCtrl', [
'$scope',
'Auth',
function($scope, Auth){
$scope.signedIn = Auth.isAuthenticated;
$scope.logout = Auth.logout;
Auth.currentUser().then(function (user){
$scope.user = user;
});
$scope.$on('devise:new-registration', function (e, user){
$scope.user = user;
});
$scope.$on('devise:login', function (e, user){
$scope.user = user;
});
$scope.$on('devise:logout', function (e, user){
$scope.user = {};
});
}]);
applicaton_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
respond_to :json
def index
end
end
I have Devise gem installed, and using angular, angular-ui, angular-devise in Bowerfile
It looks like changing :exception to :null_session worked.. Why is this?

DELETE not found; rails + angular

CODE:
Rails controller:
def destroy
respond_with Post.find(params[:id]).destroy
end
Angular factory:
.factory('posts', [
'$http',
function($http) {
var o = {
posts: []
};
o.destroy = function(post) {
return $http.delete('posts.json', post).success(function(data) {
o.posts.splice(o.posts.indexOf(data), 1);
});
};
return o;
}
]);
Part of a main module:
angular.module('flapperNews', ['ui.router', 'templates', 'Devise'])
.config([
'$stateProvider',
'$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'home/_home.html',
controller: 'MainCtrl',
resolve: {
postPromise: ['posts', function(posts) {
return posts.getAll();
}]
}
})
}
]);
mainCtrl.js:
angular.module('flapperNews')
.controller('MainCtrl', [
'$scope',
'posts',
function($scope, posts) {
$scope.posts = posts.posts;
...
$scope.destroy = function(post) {
posts.destroy(post);
};
}
]);
PROBLEM:
When trying to click on delete button ng-click="destroy(post)" - it doesn't work and gives me the error:
DELETE http://localhost:3000/posts.json 404 (Not Found)
The interesting part is when I change my $http.delete to $http.post - it works, but on refresh I have 2 same posts(obviously).
I am a newbie in both angular and rails, so I would really appreciate your help.
Rake routes:
Make sure you have resources :posts in your rails routes file.
Okay, I got this.
The problem was in this row: return $http.delete('posts.json', post). Need to change this to
return $http.delete('/posts/' + post.id + '.json'), as rake routes says it should be.

automatically redirect page in angularjs

In a angularjs project, I want when user doesn't sign in, page is automatically redirect to login page. For this, I when user want see a page, if doesn't sign in before, I send 401 from rails sever by below code:
def failure
render :status => 401, :json => { :success => false, :info => "Login Credentials Failed" }
end
and I recieve this in chrome browser:
GET http://localhost:3000/api/record.json 401 (Unauthorized) angular.min.js?body=1:81
(anonymous function) angular.min.js?body=1:81
t angular.min.js?body=1:76
f angular.min.js?body=1:74
I angular.min.js?body=1:102
I angular.min.js?body=1:102
(anonymous function) angular.min.js?body=1:103
h.$eval angular.min.js?body=1:114
h.$digest angular.min.js?body=1:111
h.$apply angular.min.js?body=1:115
t angular.min.js?body=1:75
y angular.min.js?body=1:79
x.onreadystatechange
And I have below code in angularjs controller to redirect page:
'use strict';
angular.module('app',['ngRoute', 'ngResource', 'sessionService', 'recordService'])
.config(['$httpProvider', function($httpProvider){
$httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content');
var interceptor = ['$location', '$rootScope', '$q', function($location, $rootScope, $q) {
function success(response) {
return response
};
function error(response) {
if (response.status == 401) {
$rootScope.$broadcast('event:unauthorized');
$location.path('/users/login');
return response;
};
return $q.reject(response);
};
return function(promise) {
return promise.then(success, error);
};
}];
// $httpProvider.responseInterceptors.push(interceptor);
$httpProvider.interceptors.push(interceptor);
}])
.config(['$routeProvider',function($routeProvider, $locationProvider){
$routeProvider
.when('/', {controller: 'HomeCtrl', templateUrl: '<%= asset_path('templates/index.html') %>'})
.when('/record', {controller: 'RecordCtrl', templateUrl: '<%= asset_path('templates/record/index.html') %>'})
.when('/users/login', {controller: 'UsersCtrl', templateUrl: '<%= asset_path('templates/users/login.html') %>'})
.when('/users/register', {controller: 'UsersCtrl', templateUrl: '<%= asset_path('templates/users/register.html') %>'})
.otherwise( {redirectTo: '/'});
}]);
Now when I run project and I want accept localhost:3000/#/record, I see the record page without data and page doesn't redirect to login page. How can I fix this probelm and solve it?
You can do like:
angular.module('myapp')
.factory('httpInterceptor', ['$q', '$location',function ($q, $location) {
var canceller = $q.defer();
return {
'request': function(config) {
// promise that should abort the request when resolved.
config.timeout = canceller.promise;
return config;
},
'response': function(response) {
return response;
},
'responseError': function(rejection) {
if (rejection.status === 401) {
canceller.resolve('Unauthorized');
$location.url('/user/signin');
}
if (rejection.status === 403) {
canceller.resolve('Forbidden');
$location.url('/');
}
return $q.reject(rejection);
}
};
}
])
//Http Intercpetor to check auth failures for xhr requests
.config(['$httpProvider',function($httpProvider) {
$httpProvider.interceptors.push('httpInterceptor');
}]);
than in the route
.state('user_actions', {
abstract: true,
templateUrl: 'users/views/actions.html',
resolve: {
hasaccess: function(Sessions){
return Sessions.hasAccess('users');
}
},
controller:'UserParentActionsController'
})
.state('user_actions.create', {
url: '/user/create',
templateUrl: 'users/views/create.html',
resolve: {
groups: function(Groups){
return Groups.getList();
}
},
controller:'UserCreateController'
})

AngularJS MVC 4 routing, html5 hashbang urls

I have angularjs and mvc4 app. For using disqus I enabled hashbang and html5Mode url.
With html5 mode, server side url rewriting needs to be fixed. otherwise a full page refresh leads to 404 error.
The entry point of my application is Index.chtml in home controller and it uses _layout.chtml (for bundling and minification.)
My webconfig route is :
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{*url}",
defaults: new { controller = "Home", action = "Index"},
namespaces: new[] { "Flashspark.Controllers" });
and my AngularJS config is:
(function () {
'use strict';
var app = angular.module('app');
// Collect the routes
app.constant('routes', getRoutes());
// Configure the routes and route resolvers
app.config(['$routeProvider', '$locationProvider', 'routes', routeConfigurator]);
function routeConfigurator($routeProvider,$locationProvider, routes) {
routes.forEach(function (r) {
$routeProvider.when(r.url, r.config);
$locationProvider.html5Mode('true').hashPrefix('!');
});
$routeProvider.otherwise({ redirectTo: '/' });
}
// Define the routes
function getRoutes() {
return [
{
url: '/',
config: {
templateUrl: 'app/thoughts/thoughts.html',
title: 'thoughts',
settings: {
nav: 1,
content: '<i class="fa fa-book"></i> Thoughts'
}
}
}, {
url: '/faq',
config: {
title: 'faq',
templateUrl: 'app/faq/faq.html',
settings: {
nav: 2,
content: '<i class="fa fa-info"></i> FAQ'
}
}
},
{
url: '/timeline',
config: {
templateUrl: 'app/timeline/timeline.html',
title: 'timeline',
settings: {
nav: 3,
content: '<i class="fa fa-arrows-h"></i> Timeline'
}
}
},
{
url: '/about',
config: {
templateUrl: 'app/about/about.html',
title: 'contact',
settings: {
nav: 4,
content: '<i class="fa fa-list fa-1x"></i> About'
}
}
},
{
url: '/thoughts/:article',
config: {
templateUrl: 'app/article/article.html',
title: 'article',
}
}
];
}
=================================================================================
THE PROBLEM I AM HAVING:
With this configuration, All the routes which are only 1 deep work without any issues
like:
/faq , /timeline
even after refresh, the url's are preserved.
However for URL's like:
/thoughts/:articleid (2 deep)
the styling for the whole app is stripped out when I refresh from this page.
You need to have to a default route for thoughts
{
url: '/thoughts',
config: {
templateUrl: 'app/article/article.html',
title: 'article',
}
}

Resources