I want to implement authorization in AngularJS. In my project which is some kind of social media, different roles or even same roles may see a view file differently.
For example imagine we have two different roles: customer and company.
A customer and a company may have different things in a shared view file, for example a company can have rate on his profile while a customer can't. (different roles).
Or a customer may see a button in a page while another customer can't. (same roles)
As you can see I can't implement authorization by simply checking the roles, and in some situations I need to communicate to the server.
I have multiple choices:
Create a variable in my controller's scope with corresponding permissions, which they have default value of false:
$scope.auth = {
canRate: false,
isConnected: false
};
Then connect to server and change the value of auth object based on the response. And use ng-if in my view files to show or hide elements.
Create a directive and pass comma-separated permissions to it.
<button auth="canRate,isConnected"></button>
Then connect to server to check the permissions. If all of them where true, then show the element.
Use resolve: {...} and get all necessary data from the server when routing, which increases loading time of each page.
I want to know is there a better approach to solve this problem?
Any kind of help or comment would be greatly appreciated.
Note: Of course I have server side authentication and authorization! I just want to show some elements in a view file based on user roles or some other conditions which I explained. And this elements are something like a button or a link, otherwise instead of using a shared view and hiding elements, I could use different views for each situation.
Any how, I know this approaches are for display purposes only, and they can not solve security challenges.
First things first, I LOVE AngularJS. But, like all web client frameworks, in a strict sense you can't implement Authorization in AngularJS.
You can not trust the web client to hide data from the user. If the server sends the data to the client, they can still find a way to see it (using fiddler for example) even if you use ng-hide to avoid displaying it.
So, you must implement Authorization on the server side. Now then, assuming you do that:
AngularJS is great for building dynamic web interfaces based on the data you receive from the server. So, your server should only send the data your client is allowed to see. Then, you can use ng-hide or ng-if to avoid displaying the components that would otherwise show that data.
Furthermore, your server can even send an object that contains the list of possible actions available to the user. And then you could use ng-hide in your buttons so as not to show them when the action isn't available.
Even still, you will need to code your server side to ignore actions that the user isn't allowed to take.
Your approach will work, but it is not secure. I would make sure that the server handles the authentication as well. Personally, I've always used a server-side token based authentication system when working with AngularJS.
Instead of using ng-if, you should make your GET or POST requests require the token given on login. From there the server can determine whether or not to allow the request to succeed, with no chance of the user faking credentials. Both of your examples work fine, but use them as a means to hide things for display purposes only. The web client will NOT keep sensitive information safe or prevent the possibility of POST requests from unwanted users.
Related
I'm wrestling with trying to authenticate in an AngularJS application using PKI. All of the questions and examples I've seen show authentication using a login/password instead. However, I am running on an intranet, where we use PKI keys consistently. I've read the various suggestions online, but none seem to discuss my particular architecture.
The Angular side contains multiple pages/controllers, and I have no way of controlling which page the user visits first. I need the authorization information on each page.
The application is set up with a NodeJS REST service to get the user's authorizations and other information based on the user's public key (passed in thru the certs). Since the NodeJS service must contact external servers, I want to only invoke it only once, and retain an authorizedUser object (probably in rootScope?)
I've looked at creating services, providers, etc. But none seem to fit this challenge. To summarize:
Authorization using PKI certs, not login/password
Certs used to reach NodeJS REST service, but must only be invoked once
Multiple Angular controllers/pages need authorization information
What would be the best approach here?
OK - I figured it out. My approach was to put the webservice call to the NodeJS backend in the module.run(), and set the $rootScope within the $http.get().success() block. The NodeJS backend gets the certs from the webservice call, and does the lookups it needs to do.
I'm not sure if that's the best approach, but it works for now.
In Laravel, you can restrict access to some Controllers (eg. Admin-related controllers such as Admin/UsersController, Admin/SettingsController, etc.) to specific user sessions. Because it's server-side, the user has no-way to snoop-out about such controllers unless authenticated.
In the case of AngularJs's, the code resides in the browser. Thus, anyone can get a look at the javascript source codes and might figure-out the behaviour of the app. Say he might discover that there are controllers that manage admin-related data. Or anyone might try to brute-force-search the app's URL for javascript files to observe. Say he looks at http://myapp.com/AdminSettingsController.js in which authenticated users should only be able to see or should not at all.
Going back to the main question, how do you resolve such issues?
This problem has only one solution. Treat JavaScript as language for your User Interface only. Nothing more than that. Don't store any sensitive data in browser, don't store any sensitive logic (e.g. database queries) either. There is no way to hide network traffic or source code from client.
I usually create some sort of user object on client side, which contains users role for resolving permissions, and I use the permission for display controls, e.g. show some buttons only to admin etc. BUT, this only affects the displaying of the page, If user interacts with that controls, the controls rely on the server and if the user does not have proper permissions on the server as well, the interaction with the control fails, so if anyone with some knowledge change the user object on the client and grants him administrator role, he only sees the control what the administrator would see, but he can not make administrator actions nor he sees any sensitive data.
What is the standard practice in Meteor for controlling users access for certain sensitive pages? For example, only users with Admin level can access CRUD operations, so what is the best method to block/allow users access these pages?
I know that we can use publish to limit the user accessibility to data, but for pages, what is the best way?
I am thinking of checking the user level during the rendered but again, I am not sure if this method is safe.
There is currently no method of denying access to a page, as the whole client code is packed and sent as one application. Since the code for restricted page is in the browser, user can access the page easily.
What you can do is to restrict access to data displayed on those pages. There are two things to be done:
Specify what data the user can see. This is done via the publish and subscribe methods. In the Meteor.publish method you can check user privileges and decide which objects user can see, and which fields of those objects.
Specify what data the user can change. This, as stated in the other answer, is achieved by Collection.allow and Collection.deny methods, which allow you to check user privileges on each CRUD operation and decide whether it's allowed.
The only places you need to control the user's level are in publish and in allow/deny callbacks. By controlling it in publish, you make sure the user does not receive any information it shouldn't know, and by controlling it in allow/deny callbacks, you make sure the user does not add/edit/delete information it's not allowed to.
If you're using custom methods for CRUD operations (on the server), this is a third place where you need to control the user's level (allow/deny callbacks are only checked against CUD operations made on the clients!).
Edit
For examples on how to use the allow callback, see http://docs.meteor.com/#allow The deny callback works in a similar (but opposite) way. At least one allow callback must return true and all deny callbacks must return false in order for operation to be granted.
I need to understand and maybe ideas about single page apps.
I want to create a project, i'll do it with MVC. I also want to use AngularJS for client side programming.
I know that AngularJS is good for single page applications and when working with SPAs you send your data to API to process. But data sent from Angular is visible to user and open to be manipulated.
I don't want users to be able to see any data or access to the API from the internet. Witch way i should follow?
I'm thinking about keeping sensitive user data in MVC controller. For example let's say user Id is very sensitive for my project. If i keep user id in javascript variable, when i'm sending it to API with some command user will able to change the id and manipulate the system. But if i keep user-id in MVC controller, via user authentication, and send request to my MVC controller then the user won't be able to change it. But i know this is not the best way of doing things, there must be a more clever way.
I'll be glad if someone can explain how this things works in SPAs or when you use Angular and MVC together.
This won't work, you can't prevent user from tampering the data, crafting custom request and doing whatever she wants at her side.
What you should do is to never trust upcoming data - which means validate every incoming id twice, once when you produce it and then when it comes back. Either it comes plain and you verify if it's legal or you encrypt it so when it comes back you decrypt it.
Some data can be stored at the server side, the id you mention is such example. This way user never sees the data, what you pass is the session id which is a long random value, rather impossible to craft. This approach comes with the cost of server side resources that are used, the more users the more resources at the server stored between requests.
I'm new with angularjs...
I read the docs, and completed the tutorial; i also tried something else by myself, and things start to make sense to me.
Now i wonder how to make a safe authentication system.
The easy part: no code, i will describe operations my code execute:
I've a classic form: username, and password text input.
The user fills the form, and press ENTER.
An ajax request starts, and the response is a JSON telling me
something like "ok i know you" or "i don't know who you are".
What i need now is to mantain the logged status of the visitor (or not logged) between the different views of my application.
I read on the internet that, to achieve this objective, someone sets a variable ($scope.isLogged = true), someone else uses cookies; but javascript variables, and cookies can be easily edited using firebug, or similiar development tools.
... and finally the question:
So, have you some suggestion to achieve a safe authentication system in an angularjs app?
You cannot authorize anything in angularjs, because the user has full controll of the execution environment (namely, the browser). Each check, case, if - anything you can think of - can be tampered with. There are javascript libraries that use asymmetric keys to perform local encryption to store local data somewhat safely, but they are not what you are looking for, really.
You can, and you should, authorize things on the server - the standard way you would do it in an ordinary application - using session; no special code is necessary, ajax calls use ordinary session cookies. Application does not need to know whether it's authenticated or not. It only needs to check what server thinks.
From the perspective of your angularjs application, being "logged in" or "logged out" is merely a gui hint for the user.
Probably you found a solution, but currently I made up an authenticaiton scheme I'm implementing in my Angular App.
On .run the app is registered with an ActiveSession set to false.
It then checks if the browser has a cookie with a token and a userId.
If YES, check token+userId on server and updates the token on both server and local (token it's a server generated key unique for each user)
If NO shows login form, check credentials and again if they are valid does a server request t get a new token and saves is locally.
The token is used to make a persistent login (remember me for 3 weeks) or when user refreshes the browser page.
Thank you
I asked this question three months ago.
I would like to share what has become my favourite approach when I've to deal with user authentication in a web app built over AngularJS.
Of course fdreger's answer is still a great answer!
You cannot authorize anything in angularjs, because the user has full
controll of the execution environment (namely, the browser).
From the perspective of your angularjs application, being "logged in"
or "logged out" is merely a gui hint for the user.
So, briefly my approach consists in:
1) Bind to each route additional information about the route itself.
$routeProvider.when('/login', {
templateUrl: 'partials/login.html', controller: 'loginCtrl', isFree: true
});
2) Use a service to mantain the data about each user, and their authentication status.
services.factory('User', [function() {
return {
isLogged: false,
username: ''
};
}]);
3) Everytime the user try to access a new route, check if they have the grant to access.
$root.$on('$routeChangeStart', function(event, currRoute, prevRoute){
// prevRoute.isFree tell me if this route is available for all the users, or only for registered user.
// User.isLogged tell me if the user is logged
})
I also wrote about this approach (more in detail) on my blog, users authentication with angularjs.
First of all: Client-side data can always be manipulated or tampered with.
As long as valid session IDs aren't easily guessable and measures like associating session tokens with the client's IP there is no big deal about it.
You could, in theory, also encrypt the cookie, as long as you do so on the server side.
For details on how to encrypt your cookies, see the docs of your server-side (e.g http://expressjs.com/api.html#res.cookie for Express.js)
You need to learn about the server side / database end of it.
User logins need to be stored somewhere - 99.9% of the time this is in a server side database.
Ideally for a really secure system you want a backend (server side) membership system that stores the session in a database table that is related to the member table that holds the encrypted password, but also provides a RESTful interface where you can build your api calls to.
One Script that I've used successfully a lot has been Amember https://www.amember.com/. It's a really cost effective way to go although there are a lot of other script out there, I've had a lot of success with this one.. It's also PHP so you can build your build out an API for your angular http calls really easily.
All of these javascript frameworks are great but the effect is that now too many are focusing too much on the front end of things - learn the database / backend as well! :-)