I'm facing an issue on how to implement route restrictions based on remote data gotten from the server.
Suppose I have the following config file:
angular.module('myApp')
.config(['$stateProvider', function($stateProvider) {
$stateProvider
.state('post', {
url: '/post/:post_id',
abstract: true,
[...]
})
.state('post.view', {
url: '/view'
[...]
})
.state('post.edit', {
url: '/edit'
[...]
})
}]);
The requirements for my application are:
A post has an owner (creator of the post) and its domain may be public or private.
If the domain is public, every user will be able to see the post (entering state post.view), and, if not (domain is private), only the owner will be able to see it.
The post.edit state is only accessible to the owner.
To do this, what is the best approach?
I was thinking of having a resolve promise that fetches the data from the server (post's domain and correspondent user role), performs the required checks and returns accordingly (promise resolved or rejected).
But then, how would I redirect the user to a correct state if he is not authorized? For example, a common user trying to access the post.edit state should be redirected to the post.view state, if the post's domain is public... But if the post's domain is private, an unauthorized access page should be presented. Is it a good approach to do this directly on the resolve? What are the alternatives?
Have a look at this great tutorial on routing authorization based on roles:
role based authorization
Also have a look at this stackoverflow answer, here there is conditional routing based on login, you can use the same logic of roles for your purpose,
Ui-router, routes based on permission
Related
My application has a guest mode. I want to block access to endpoints that need signing in.
Lets say I have the following snippet:
app.use('/api/user', authRoutes);
// profile route
router.get('/:userId', viewAction); // <- visits profile, allowed for guests
router.get('/:userId/follow', followAction); // <- follow profile, not allowed for guests
Now I could just check inside followAction if the user is a guest or not, but I want to do it the other way around. So I want to block all routes except for ones which have specified they allow guests. (so I don't accidentally forget to check for auth)
I was thinking of something like an array of allowed endpoints for a guest, but this doesn't work since the 'dynamic' endpoints won't match.
const guestEndpoints = ['/user/i_cant_just_put_a_userId_here']; // <- missing :userId here.
Is it possible to do something like this?
router.get('/:userId', viewAction, allowedForGuests);
I think this should be quite easy to do, am I missing something?
I would suggest looking into a 'jwt' library and adding a middleware for those specific protected routes. JWT (json web token) works by sending the client a token when they log in that is then cached on the client side and requiring that token to be sent with each request to access protected routes. The token is usually set in the headers.
Here is a good article to get started on middleware...
http://expressjs.com/en/guide/using-middleware.html
And here is the jwt npm module that I prefer...
https://www.npmjs.com/package/jsonwebtoken
Previous posts — 1 , 2
What I have now: AngularJS app with two controllers. First works with CouchDB documents and the second perform sign-in requests to example.com/demo/_session.
When I open application, I can't do editing with couchdb (in first controller), because some actions I've limited to logged users only. In second controller I'm sending simple POST over $http, which return Http-only (so no cookie magic there) auth cookie AuthSession. That cookie bound to couchdb address and in theory any request from page to couchdb address must contain that cookie also.
But this no happens. No one call to couchdb, except calls to /_session comes with AuthSession cookie. E.g. example.com/demo/_session getting with AuthSession and example.com/demo/records not.
In learning Angular and CouchDB I came to deadlock.
What I'm doing wrong? I do not want to hide couchdb behind something with custom auth — too complex and not a good way, I think.
UPD: Getting Set-Cookie header also fails — it not available in HttpPromise.success(function (data, status, headers, config)) headers. I'm tried to get it like headers("Set-Cookie") — no luck.
Maybe something wrong in couchdb configuration? I've uploaded it to pastebin.
Check CORS to be enabled (* in my cause)
Check cors/credentials in config, it must be true
Use {withCredentials:true} in Angular $http
Now it works.
I have an application set up with the Mean.js yeoman generator. It uses PassportJS to setup local-authentication. This all works great and I understand how to check if a user is logged in from the ExpressJS routes file.
The problem is that most of my page routing is done in the angular routes. I know how to check authentication in the controller with the the following code.
// Projects controller
angular.module('projects').controller('ProjectsController', ['$scope', '$stateParams', '$location', 'Authentication', 'Projects',
function($scope, $stateParams, $location, Authentication, Projects) {
$scope.authentication = Authentication;
But how do I check authentication in the routes. For example in this routes files how would I only allow authenticated users to access the tools html file and redirect users that arent logged in back to the home page:
'use strict';
//Setting up route
angular.module('analysis').config(['$stateProvider',
function($stateProvider) {
// Projects state routing
$stateProvider.
state('imageAnalysis', {
url: '/analysis',
templateUrl: 'modules/analysis/views/tools.client.view.html'
});
}
]);
I know there are similar posts out there but I had trouble understanding many of them. Thanks, I really appreciate any help. I am new to the stackoverflow community and still learning community standards.
At a high level, there are two approaches:
Use your view routing layer (e.g. UI Router) to catch “unauthenticated” state
Use HTTP interceptors to look for requests that have a 401 Unauthorized status, indicating that the user must login (or that their current session has expired)
In practice you’ll probably use a combination of both.
Speaking to the UI Router, there a two of doing this: resolves or events.
Resolves: The UI Router provides a nice feature called resolves, which allows you to provide a promise that must be resolved before the view is rendered. You could create a promise which resolves your user state.
Events: The UI Router provides a $stateChangeStart event, you can observe this event and prevent it if the user is not logged in. You would then send the user to login page. This is a bit more stateful (you have to remember where the user wanted to go in the first place, so that you can redirect after login).
I chose the event approach for my work on the Stormpath Angular SDK because it gives me the flexibility to define authorization on top of authentication.
You may be looking for HTTP Interceptors. Check auth on the requests.
From OneHungryMind:
HTTP interceptors are a great way to define behavior in a single place
for how a request or response is handled for ALL calls using the $http
service. This is a game changer when you want to set an auth token on
all outgoing calls or respond to a particular HTTP status error at the
system level. You can pair interceptors with the incredibly useful
Angular Storage module to cache an authenticated user and retrieve it
the next run time.
There are some good tutorials(1) out there(2)!
Currently I'm implementing ng-token-auth into my Angular application, while this works great, I'm having some trouble with restricting access to certain pages.
In some of my routes I have a couple of extra parameters:
data: {
title: 'Dashboard',
restricted: true, // Only allow logged in users
role: 2 // Only allow a specific role
}
I'm doing this checking login in $stateChangeStart, so before I switch routes, I can check if the user is allowed to that route.
I followed the ng-token-auth suggestions about using a parent route with a resolve to check if a user is logged in or not:
resolve: {
auth: function($auth) {
console.log('validate user');
return $auth.validateUser();
}
}
Now the problem comes when I first load up the application, obviously the $stateChangeStart event is fired before the $auth.validateUser() has been resolved, because of that the login inside the $stateChangeStart fails and the user is redirected to the login page.
What would be the better way of implementing this "permissions logic", I don't want to do it per route, as that would add in a lot of extra work and code.
Doing it in the $stateChangeStart also doesn't seem to be the best options as that doesn't work on first load.
I would treat Authentication and Authorization as two different things.
ng-token-auth helps you with Authentication. It even helps you with selecting which routes must be available for authenticated users Refer to example-using-angular-ui-router
role: 2 // Only allow a specific role
seems more of authorization and permissions. For that you may want to take a different approach. One such approach. We took a similar approach - we also made sure some of the authorization was fetched upfront.
I was wondering how can I track the current logged in user in a backbone.js app, Most of the views on the page need to know if the user is logged in or now and which user is logged in. What is the best method to achieve this?
I have session management on the server but how do I know which user am I dealing with in my backbone app and how do I know if he logged out thats the question
Also how do I know that a user has logged out using another tab etc? There should be a generic way to handle this stuff, like we have before filters in rails to manage such things. What method is used to achieve the same on the front end.
What I am currently doing is that when the homepage loads I have set from my server side rendered html a hidden field #current_user_id, which the my backbone app reads and sets a variable like the follwoing
window.MyApp =
Models: {}
Collections: {}
Views: {}
Routers: {}
currentUser: null
init: ->
#currentBusiness = $('#current_business').val()
new MyApp.Routers.Businesses
Backbone.history.start()
$(document).ready ->
MyApp.init()
Then my router sets up a ShowView which then sets ups other sub views on the page
class MyApp.Routers.AppRouter extends Backbone.Router
routes:
'': 'show'
show: ->
user = new Vocallocal.Models.user id: Vocallocal.currentBusiness
Vocallocal.currentBusiness = business
new Vocallocal.Views.BusinessesIndex model: business
business.fetch()
Here is the main ShowView
class MyApp.Views.ShowView extends Backbone.View
el: '#main'
template: JST['users/home']
initialize: ->
#model.bind 'change', #render, #
#details = new Vocallocal.Views.UserDetails model: #model
#logo = new Vocallocal.Views.UserLogo model: #model
#managePhotos = new Vocallocal.Views.ManagePhotos model: #model
render: ->
console.log('change has occured')
#
does the above code and setup makes sense. I am looking on general advice if I should make any changes to the above.
Thank you for you valuable input
--Abid
Our app is a fully separated client/server API architecture, including login.
When a user authenticates and authorizes with our server we send a JSON request with the relevant data over an HTTPS connection (this means due to CORS & IE, that our backend and our front end have to be served from the same site).
The backend returns an auth token.
Every authentication-required REST API requires this token to be sent along as an Authorization header over an HTTPS AJAX request. The server is set to reject any tokens not provided by our mechanism, and reject any connections from pages which aren't served by our severs.
We store this auth token in a cookie on the client side. If the auth token is invalid, missing, etc, our server returns an HTTP 401 which we trap and redirect the client to the login page if it occurs.
I also battled wrapping my head around authentication when developing client side apps. If you have ever worked with a 3rd party API (Facebook, Twitter) you will know that all authentication is done on the server side. Thats why #Pointy is correct. No authentication is done client side.
So If you are looking to access a secure part of your API, your username and password must be sent with every request, and checked on the server. This is definitely not the most secure way, and there are very few ways to get around this without an HTTPS connection. I am not sure what language you are developing your API in, but still this link is a very good read. Steve basically uses a simple protocol whereby the client sends an authorization token as a header in the HTTP request, and the server decodes that token to decide whether or not it is valid.
In answering your question, I would check if the user is valid. If he/she is, bootstrap your user model with an authentication token. This authentication token will be sent and decoded with every api request that requires authentication. I am no expert, so if there is any other way, please let me know. I am also still learning this.