When it comes down to good RESTfull setup, what is the best practice for providing results that pertain to the owner as the requestor and results that pertain to a user wanting data owned by another user.
I have read that a resource should have max 2 base URLs so how to handle say,
Get all items for authenticated user
Get a single item for Authenticated user
Get all items for a particular user
Get a single item for a particular user
Although your question is a bit unclear, it seems to me you might mix up "Resources" as in HTTP resources, and Model objects or database rows.
The two do not necessarily have a 1-to-1 relationship, or even 1-to-2 relationship as you seem to imply. You can expose a database row in multiple "forms" as resources, there is no limitation how many times you can aggregate, transform or publish the same information, as long as those are all semantically different things.
So, back to your problem. You can publish resources pertaining to the authenticated user, and just users independently which might also contain the current user. With an URI structure for example like this:
/currentuser
/user/1
/user/2 <- might be the same as /currentuser
/user/3
...
There also could be a list of users recently logged in:
/recentuser/444
/recentuser/445 <- might be again /currentuser
...
That would be a third reference on the same user, but it is ok, because all of those have a different meaning, might even have different representations to offer (one might offer more information than others).
Related
I can restrict entire controller action access with [Authorize(Roles=...)] however, what about if I want to allow a user to for example look at the data of the other users in their own department (only).
Specifically what I mean is when I give a user the details of another user, the URL will be like this:
myapp.com/user/details/45
And they could quite easily just edit the 45 to be whatever they want. I want to restrict the access if the user the requested is not part of their own company (their company is currently in their session but that can be changed)
I can see a few different ways to do this, but I am just wondering what everyone's preference is based on experience. Here are some options:
1.Change the way access is done by editing the routing. myapp.com/Company/4/User/4' where 4 is a psudoID which references an actual ID internally.
2.myapp.com/OurCompany/User/4' < same but with a controller for ourcompany instead of generically companies.
3. Just check it internally by checking the requested user is in the same company: `myapp.com/User/42345'. My issue is that this has to be customized for each kind of request (users, products, related companies). But this is what I'm looking at right now.
EntityFramework actually has the power to reference the company members of the current user because when they log in I get their company entry and store it in the session. This allows easy access to the members of the company like so:
SessionHandler.UserSession.CompanyTable.UserTable.Where(e=> e.UserID == id).FirstOrDefault();
This seems odd to those who don't know about EF, but basically the subtable UserTable is a subset of all users referenced by the Foreign Key of the CompanyTable, which does indeed return the correct set of entities. The issue with this is that updating the entry in this way actually updates the entry in the SESSION but not inside the DATABASE, which is really bazaar to watch because it means the logged in users can seemingly make changes to the database but infact they are just being saved into the session. (staring at the database whist making these changes confirmed it, logging out and logging in nothing was saved, but db.SaveChanges() was correctly being called, just there were no changes to be made)
First, for the love of everything good and holy, stop putting that in the session. The session shouldn't be used for this, regardless, and it's code smell of the worst kind.
What you're talking about is object-level permissions. The correct way to do that is to limit your queries with some identifying factor of the currently logged in user. Your entities need a concept of "ownership" for this work. In other words, they need a foreign key to some other entity that "owns" that particular instance. Since here you want to restrict by department, that means all your users need to be owned by departments. Then, for situations like this you can do something like:
db.Users.Where(m => m.DepartmentId == user.DepartmentId)
Where user here is the instance of the currently logged in user. By querying in this way, the subset of entities available to the user is restricted by the user, itself. Which means attempting to access a URL with id outside of that set will naturally result in a 404. A 404 is actually the best thing for this, because even though it's authorization based, returning a 403 lets you know something is there - you just can't access it. For a hacker, this kind of information is half the battle. A 404 being returned gives you zero information. It might not exist or it might just not be available to you.
First of all, I want to apologize for my terminology. I am not entirely sure what to call what I am looking for, so I can’t google for answers. But here is my problem.
I am working on a Rails application that stores information about different websites and provides various services for them. I will call these services ‘Products.’ One website can be subscribed to several products, and a product can be served to various websites. So here is a very simple association scheme for these relationships:
At least, it would have been simple, but the problem is that the Settings model (shown in red on this diagram) is different for each product: for one product, it will have one number of fields and data types, for another it will have a different number of fields with different data types. On the other hand, the Faq and Description are the same, so if I redraw the diagram as follows:
I will get another problem: too much repetition (shown in blue on the diagram). Ideally, I want some kind of modification of the first diagram, where the Product model will choose differens Settings models depending on a parameter that I pass to it:
So that a request website.products.find(1).settings will return the model Settings1, while a request website.products.find(2).settings will return a completely different model, Settings2.
Is this achievable in Rails? If not, how would you organize such data?
I've been using /d2l/api/lp/1.4/enrollments/myenrollments/ to get a list of enrollments for the current user. Now, I want to just get the enrollments where the user is in an instructor role. So, I'm trying to use:
/d2l/api/lp/1.4/enrollments/users/{userId}/orgUnits/?roleId=105
When I use that, I get an empty list of Items back, with or without the roleId specified.
My expectation is that just calling it without the roleId would return the same list as /d2l/api/lp/1.4/enrollments/myenrollments/. But, I always get an empty list, except when I log in as a system administrator. Only in that case do I get anything back.
Does anyone have any suggestions on what I might be doing wrong?
The various my* API calls specifically exist to provide end users to fetch back details about the system that they should know, but segregated from information they shouldn't (that's available through the more general routes for a particular area). Enrollments is a good example of this. And end-user should be able to see their own enrollments, but they should not have generalized access to enrollment records. In particular, the D2L system treats the D2L user role belonging to an enrollment as fairly privileged information, and a side effect of this is that it's not generally visible to end users.
One way that applications and services can cope with achieving goals that the end-user cannot themselves perform is to have set up a "service account" that the app can use to make calls of an administrative nature, to fetch back data that they can use in the business logic around presenting information to end users. In this particular case, you could, for example use the service account to make calls about a user's enrollments, and then present the user with logic that could filter the list of their enrollments by "these are the student ones, and these are the ones where you're a teacher, and a tutor, and so forth".
But you'd also need to carefully consider the implications of this type of activity in balance against the intentions of the client LMS's policies and administration. Even this level of information may be giving away too much to end users, in the eyes of a client LMS administrator.
Using a service account to let an app make administrative level calls must always be done with great care around the issue of information/functional leakage to end users.
I am using embedded documents in MongoDB for a Rails 3 app. I like that I can use embedded documents and the values are all returned with one query and there is less load on the database server. But what happens if I want my users to be able to update properties that really should be shared across documents. Is this sort of operation feasible with MongoDB or would I be better off using normal id based relations? If ID based relations are the way to go would it affect performance to a great degree?
If you need to know anything else about the application or data I would be happy to let you know what I am working with.
Document that has many properties that all documents share.
Person
name: string
description: string
Document that wants to use these properties:
Post
(references many people)
body: string
This all depends on what are you going to do with your Person model later. I know of at least one working example (blog using MongoDB) where its developer keeps user data inside comments they make and uses one collection for the entire blog. Well, ok, he uses second one for his "tag cloud" :) He just doesn't need to keep centralized list of all commenters, he doesn't care. His blog contains consolidated data from all his previous sites/blogs?, almost 6000 posts total. Posts contain comments, comments contain users, users have emails, he got "subscribe to comments" option for every user who comments some post, authorization is handled by the external OpenID service aggregator (Loginza), he keeps user email got from Loginza response and their "login token" in their cookies. So the functionality is pretty good.
So, the real question is - what are you going to do with your Users later? If really feel like you need a separate collection (you're going to let users have centralized control panels, have site-based registration, you're going to make user-centristic features and so on), make it separate. If not - keep it simple and have fun :)
It depends on what user info you want to share acrross documents. Lets say if you have user and user have emails. Does not make sence to move emails into separate collection since will be not more that 10, 20, 100 emails per user. But if user say have some big related information that always growing, like blog posts then make sence to move it into separate collection.
So answer depend on user document structure. If you show your user document structure and what you planning to move into separate collection i will help you make decision.
I'm trying to figure out what the best way to show a list of members (users) that aren't a collection (group).
/users
is my route for listing all of the users in the account
/group/:id/members
is my route for listing all of the users in the group
/users?not_in_group=:id
is my current option for showing a list of users NOT in the group. Is there a more RESTFul way of displaying this?
/group/:id/non_members
seems sort of odd…
Either query parameters or paths can be used to get at the representation you want. But I'd follow Pete's advice and make sure your API is hypertext-driven. Not doing so introduces coupling between client and server that REST was intended to prevent.
The best answer to your question might depend on your application. For example, if your system is small enough, it may suffice to only support a representation consisting of a list of users and their respective groups (the resource found at /users). Then let the client sort out what they want to do with the information. If your system has lots of groups and lots of users, each of which belongs to only a couple of groups, your available_users representation for any group is likely to be only slightly smaller than the entire list of users anyway.
Creative design of media types can go a long way to solving problems like this.
Spoke with my partner. He suggested:
/group/:id/available_members
Seems much more positive.
The main precept of REST is "hypertext as the engine of application state". The form of the URI is irrelevant, what matters is that it is navigable from the representation returned at the application's entry point.