Devise Angular Authentication - ruby-on-rails

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?

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.

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.

AngularJS Devise authorization

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.

Controller actions being executed as soon as the page loads

I'm using rails with devise, and angular with ng-file-upload.
I have two problems. first as soon as I go to the root of the website a POST request is executed to try to sign in the user with results in a 500 status code response.
It says it can't find the users_url, which makes sense because I don't have in my routes, what is weird is that request being fired.
Also using the ng-file-upload, when I load a dialog to upload a file, the dialog loads and it sends the request to upload the file directly. With no wait in between.
Why is this happening?
THis are the differents files being excuted in all this actions:
app.coffee
app = angular.module("inkorporated", ['ui.router', 'templates', 'rails', 'Devise', 'ngFileUpload', 'ngDialog'])
.config(['$stateProvider','$urlRouterProvider',
($stateProvider, $urlRouterProvider)->
$stateProvider
.state('home', {
url: '/home'
templateUrl: 'home/_home.html'
controller: 'SearchCtrl'
})
.state('login', {
url: '/login'
templateUrl: 'auth/_login.html'
controller: 'AuthCtrl'
onEnter: ['$state', 'Auth', ($state, Auth)->
Auth.currentUser().then ->
$state.go('home')
return
return
]
})
.state('register', {
url: '/register'
templateUrl: 'auth/_register.html'
controller: 'AuthCtrl'
onEnter: ['$state', 'Auth', ($state, Auth)->
Auth.currentUser().then ->
$state.go('home')
return
return
]
})
.state('user', {
url: '/user/{id}'
templateUrl: 'users/_user.html'
controller: 'UserCtrl'
})
$urlRouterProvider.otherwise('home')
return
])
navCtrl.coffee
angular.module("inkorporated").controller('NavCtrl', ['$scope', '$state', 'Auth',
($scope, $state, Auth)->
$scope.config = {
headers: {
'X-CSRF-TOKEN': $('meta[name=csrf-token]').attr("content")
}
}
$scope.signedIn = Auth.isAuthenticated
$scope.logout = Auth.logout
Auth.currentUser().then(
(user)->
if !!user.email
$scope.user = user
else
$scope.user = {}
return
)
$scope.$on('devise:new-registration',
(e, user)->
$scope.user = user
return
)
$scope.$on('devise:login',
(e, user)->
if !!user.email
$scope.user = user
else
$scope.user = {}
return
)
$scope.$on('devise:logout',
(e, user)->
$scope.user = {}
return
)
return
])
avatarCtrl.coffee
angular.module("inkorporated").controller("AvatarCtrl", ["$scope", "$stateParams", "Upload", "ngDialog"
($scope, $stateParams, Upload, ngDialog)->
$scope.$watch('avatar',
(avatar)->
$scope.upload($scope.avatar)
return
)
$scope.upload = (avatar)->
Upload.upload({
url: "users/avatar",
fields: { 'id': $stateParams.id }
file: avatar
})
.success(
(data, status, headers, config)->
$scope.closeThisDialog()
return
)
return
return
])
application.html.haml
!!!
%html{ "ng-app" => "inkorporated" }
%head
%meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
%meta{ name: "viewport", content: "width=device-width, initial-scale=1" }/
%title Inkorporated
= stylesheet_link_tag 'application', media: 'all'
= javascript_include_tag 'application'
= csrf_meta_tags
%body
.container-fluid
%header{ "ng-include" => "'nav/_nav.html'" }
#page-content.container
%ui-view
From what I can see here, I think there's a very good chance that the $watch is being triggered by a model change on avatar when your dialog opens. You can pretty easily remove that watch and make that function more event driven. Looking at the ng-file-uplpad docs, it looks like there's a directive attribute to specify calling a custom function like ngf-change="myFunction()"
$scope.$watch('avatar', function(avatar) {
$scope.upload($scope.avatar);
});
For the second part of your question, I'm curious to see what code is in the SearchCtrl being called on the landing page, that POST request could easily be related to something in there

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'
})

Resources