Conditional routes/ controllers

1,133 views
Skip to first unread message

tas pas

unread,
Dec 15, 2012, 1:29:52 PM12/15/12
to ang...@googlegroups.com
Hello, 
I'm trying to create a web app (using angular and php) in which users will be creating and managing pages.
To some pages they will be authorising other people to view or manage them.
If a user doesn't have the proper access rights to a page, he will presented with a small description of that page and nothing else.

Although I'm not quite sure how to do it, I have the belief that it has to be done server side and I'll have to present the users to different views or different controller for a given view, based on the server responce.

Anyone knows how can this be achieved?

Thank you

Joshua Miller

unread,
Dec 15, 2012, 3:52:28 PM12/15/12
to angular
Hi! 

This is hard to answer without knowing more about your architecture. If I make the assumption that this is a single-page application and that your PHP backend provides authentication and a RESTful interface to your page resource, then I suppose the server would, knowing the user's authorization, return only the small subset of information about that page along, perhaps, with an indication that there is more information for a higher level clearance (say, for premium users or recognized admins/moderators/owners).

In this case, on the angular side, if the displays are essentially the same only with more or less information, I would use only one view that conditionally displays the additional information, based perhaps on what is present in the server response. Perhaps also it would conditionally display information about upgrading or not being an administrator or what not based on the authorization information in the server's response. This would be more elastic than two different views or controllers by decoupling the authorization implementation from the UI representation, but there are many other ways to accomplish this too.

This contains a lot of assumptions, so if this doesn't help can you provide some more detail on your use case?


--
You received this message because you are subscribed to the Google Groups "AngularJS" group.
To post to this group, send email to ang...@googlegroups.com.
To unsubscribe from this group, send email to angular+u...@googlegroups.com.
Visit this group at http://groups.google.com/group/angular?hl=en-US.
 
 

Message has been deleted

tas pas

unread,
Dec 15, 2012, 5:24:14 PM12/15/12
to ang...@googlegroups.com
First of all thank you, because you showed me another route I haven't even thought of. :)

(I'm really restrained by my cliend so, I'm going to lie a bit here)..
I'm creating a site in which a user (an author) can create some documents (fields: text, references).
These documents can be viewed by anyone, but without the reference field unless the documents author has priviledged tha user.

Further more, the author can make other users authors as well so the other authors can edit the documents the first one made.
Something like that.

I'm trying to create this application as a single page app. I'm using the $resource service to perform queries on the database.
When the user logs in the app, the userid gets retrieved from the database and it is held on a session variable so that I can query the database using that id. Based on what you proposed, I just have to incorporate that id to all of my queries and ask the database if the user is authorised to perform that query. Does it seem legit?

Thank you


Joshua Miller

unread,
Dec 15, 2012, 8:06:36 PM12/15/12
to angular
I'm glad I could help!

In terms of authorization: your backend should have a way of indicating which users (or groups) can do what; as you said, you can just ask the database if the user's allowed. That's trivially easy. But obviously you must ensure on the server-side that the user is who they say they are with each and every request.

In terms of authentication: There's the approach of traditional websites: login with username/password and get a "session" that is valid on a particular machine for a set amount of time. Then there are the modern approaches, which are quite varied: there is basic auth, digest auth, openid, API keys, etc. But what they all have in common is something(s) is/are passed with each request to indicate the user's credentials or that the user is already authenticated.

Will you need to expose the API to something other than your angular app (say to create a mobile app or just for systems integration / SOA)? If yes, then sessions might not be the way to go.

It would appear I am incapable of providing a short reply... but I guess my answer to your question is "yes", with the above caveats.



Thank you


tas pas

unread,
Dec 15, 2012, 9:15:18 PM12/15/12
to ang...@googlegroups.com
Thank you!

So, the question now is this:

A user goes to a URL in which he/or she don't have the authorization to view.
What has happened until this moment is:
  • The routeprovider has sent the user to a view/controller pair
  • The controller invoked a service and asked for the data (or the clearance for that user) 
  • The database said that the user shouldn't be there ...
And now what? The user is in the view that I shouldn't be.

I could use the $location service in the controller (If, say, the recordset is empty or Ithe db send me a value that declares the user as non authorized) to send the user to a "you shouldn't be here" page.
But the above practice seems a little bit "hacky".

It would be better if:
  • I could load a "middle-man" controller or call a service, to check if the user should see the destination page and then send him there
  • I could change the view depending on what the controller got from the query.
The second thing of the list above is what you proposed me (which I liked) but how would be implemented, using ng-Hide maybe? I have some considerations about that because the things that I'm hiding do exist in the source code. Is there a way not to render the things I want to hide?

Sorry if I'm asking too much, but I'm really trying to understand how to do thing in angular, and I want to be exposed to different scenarios.

Thank you again for your time :)






Say that I queried the database, and it returned me an empty recordset (or something else)...

Joshua Miller

unread,
Dec 15, 2012, 10:33:04 PM12/15/12
to angular
Hello!

So far, everything we've discussed was not specific to angular. What follows is, so I should note that I am not an expert in angular (yet).

Since I don't know your application, let me make up an example. The app has two kinds of docs: drafts and published. A user is allowed to _see_ all published docs, but they can only edit or delete ones that belong to them. Also, docs can have reviews, but you're only allowed to see the reviews if you _own_ the doc. Lastly, users are _not_ allowed to see the drafts of others. Now let's consider four cases:

(1) a published doc, and the user owns it: angular gets the document data from the server. The server says the current user is the owner, so the view _would_ show the edit and delete buttons (using say ng-show). The view also displays the reviews below the document, because the user is the owner.

(2) a published doc, but the user doesn't own it: I would use the _same_ view and route as above. But the server will say the current user is NOT the owner, so your view hides the edit and delete buttons. Also, because the server _knew_ the user wasn't the owner, the server never sent the reviews this time because the user's not allowed to see them. So on your view, you are simply using ng-hide to hide an empty section of the page. Again, the server didn't send it because he doesn't own it, so there's nothing to see, so we hide the empty elements.

(3) a draft doc the user owns. Again, same view. Same as (1).

(4) a draft doc the user doesn't own: Uh oh, not authorized. This time, when angular gets the data from the server, the server _knows_ this user isn't allowed to see it, so the server will _not_ return the draft. The server will just say "not authorized" or "403" or whatever. Now angular gets this response and you can handle it in multiple ways. More on this in a second.

(5) a non-existent post: angular queries the server, which says it doesn't exist. 404 not found. More on this in a second.

The bottom line is this: authorization happens _entirely_ on the server. We are using angular to present the view slightly differently based on what the _server_ said the user could see. No data a user can't see was ever sent to angular because that would be a massive security flaw.

Okay, now for (4) and (5) to which I said I would return: you are saying that you want to redirect the user to a different route, prior to the view ever running as there's nothing for the user to see (it didn't exist or they're not allowed). In essence, your app says, "sorry, you're not allowed to see that, so let me redirect you someplace else". Since this is a single-page app, there really needn't be separate 404 or 403 views in most cases. It may be sufficient to simply say "Sorry, that doesn't exist" in an Bootstrap-like alert or a modal or whatever, because the route never changed. But you can handle it any way you want, in the same way:

The $routeProvider actually as a `resolve` property that you can use in combination with a promise. Here is some information on how you can use that in a situation like yours. These are based more on a 404, but the code essentially is the same for 403.

http://docs.angularjs.org/api/ng.$routeProvider (not a lot of info on `resolve`, but it gives a basic overview)
https://github.com/johnlindquist/angular-resolve (an example of exactly how to do this)
http://www.youtube.com/watch?v=P6KITGRQujQ (based on the above git repo)
http://stackoverflow.com/questions/11972026/delaying-angularjs-route-change-until-model-loaded-to-prevent-flicker

Also, there have been some discussions in this group on the `resolve` property before, so if you search for discussions on that, I think you'll find some more examples.

Hope this helps!

Josh

tas pas

unread,
Dec 16, 2012, 4:14:44 AM12/16/12
to ang...@googlegroups.com
Damn Josh, where's the like button?
Thank you for making everything clear by writing that huge post.  :)

Peter Bacon Darwin

unread,
Dec 16, 2012, 7:48:19 AM12/16/12
to ang...@googlegroups.com

On 16 December 2012 03:33, Joshua Miller <jo...@joshdmiller.com> wrote:
The bottom line is this: authorization happens _entirely_ on the server. We are using angular to present the view slightly differently based on what the _server_ said the user could see. No data a user can't see was ever sent to angular because that would be a massive security flaw.

^^ This really is the big take away from Joshua's post!  It is so important to recognise that the server is the only place where security can really happen. As soon as the data is released by the server there is no longer any protection in the client app.  This is primarily because the client app is easily altered to allow it to do anything with data it receives.  To re-emphasize - YOU CANNOT DO ANY SECURITY AUTHORIZATION ON THE CLIENT - you can only change the user interface to make it look more appropriate based on the authorization of the current user.  You must have a back end server that can provide the correct level of authentication and authorization to protect your data.

In our example app, https://github.com/angular-app/angular-app, we do all this with an overly simplistic NodeJS backend.  Look at the calls to "security.authenticationRequired" and "security.adminRequired" calls to see what we are doing.  It is possible to see how this could be extended to provide more sophisticated authorization.  On the client we extended Witold's original idea to provide a clever mechanism that involves a combination of a httpResponseInterceptor  and route resolves to trigger a temporary Modal dialog box to ask the user to authenticate if they hit something on the server for which they are not authorized. It looks complicated but works really nicely from a UX point of view.

Pete

tas pas

unread,
Dec 20, 2012, 7:10:50 PM12/20/12
to ang...@googlegroups.com
Peter, I'm digging in your code and I shall return with questions!
Reply all
Reply to author
Forward
0 new messages