I'm only a newcomer to ASP.NET MVC and am not sure how to achieve a certain task the "right way".
Essentially, I store the logged in userId in HttpContext.User.Identity and have written an EnhancedAuthorizeAttribute to perform some custom authorization.
In the overriden OnAuthorization method, my domain model hits the database to ensure the current user id can access the passed in routeValue "BatchCode". The prototype is:
ReviewGroup GetReviewGroupFromBatchCode(string batchCode);
It will return null if the user can't access the ReviewGroup and the OnAuthorization then denies access.
Now, I know the decorated action method will only get executed if OnAuthorization passes, but I don't want to hit the database a second time to get the ReviewGroup again.
I am thinking of storing the ReviewGroup in HttpContext.Items["reviewGroup"] and accessing this from the controller at the moment.
Is this a feasible solution, or am I on the wrong path?
Thanks!
The HttpContext.Items is alive only for the duration of the request. If you want to persist it for a longer time, you should put it in
a) session - good
b) profile - dont see the advantage
c) cookie - not recommended
d) hit the database everytime - should be OK
Store it in filterContext.RouteData.DataTokens?
Alternatively, one of the best ways to avoid hitting the database, and easiest, is caching.
Retrieve it, stick it in a cache. If it it's needed again it's already in memory and no DB hit is required. If not, then when the cache goes out of scope, so will the object.
Unless your doing a VERY big select from ReviewGroup or you have a enormous database, then a second database hit wouldn't be too much of an issue. Modern databases are very efficient at making selects, especially with properly indexed tables.
In my experience, this is the best way of doing authorisation and a similar method to how I authorized specific actions in my applications.
So in short, I wouldn't worry at all about the second database hit.
Related
Currently I have a Web API project with FluentValidation tied in to verify the requests that come in. This is working fine to make sure that the requests make sense.
My next step is to verify the request. What I mean by this is some POST (create) requests link to existing entities and may require the following checks:
I need to verify that the linked entities belong to the current user
Check to see if the user already has an 'Active' entity of the same type requested.
Check that the linked entities support the requested entity
How can I be doing these checks? I don't want to tie it into my FluentValidation as this should just validate the requests and I don't want to make trips to the DB if I'm going to return a Bad Request due to validation.
I could add these checks into each method in the controller but that doesn't seem very nice. Is there an Action or something similar that I can plug in which will be called after FluentValidation does it thing but before it hits the controller?
Thanks
Alex
It is possible to create custom Action Filters to do these checks, but in my experience it doesn't typically make sense to do so unless the thing you're trying to check is applicable to almost every request (e.g. make sure the user is logged in).
I would just put the logic for the kinds of checks you're talking about into separate utility classes where it can be easily reused, and make it the responsibility of each action to call the appropriate utility methods based on what checks need to occur for that action.
I have in the past always had quite a few problems maintaining the session state with WebMatrix, and handling them when expecting them to be timed-out (mainly because I am still learning).
The user input must always be remembered, because if they submit and a custom error occurs, I don't want them to have to re-input all of the information back into the form.
I think I have a method figured out (finally) that can properly maintain and manage timed-out session variables in the future, when they are needed.
I realize that there are several other methods of transferring data between web pages, and believe me, when applicable, they will certainly be used first. This question only pertains to when I feel like the session variable is my best option.
My problem is, I always think I have it figured out, and then, only after I have set up over half of the coding, do I realize why it doesn't quite work, and then find some sloppy (but effective) work around that will at least work for that project.
The projects I will use session variables in use the common database with web interface combination. Usually there are 3 main pages: an add entry page, an edit entry page, and a lookup entry page. The add entry page and the lookup entry page eventually post and redirect to the edit entry page.
Before I begin my next project, I thought it would be wise to inquire if my method is at least aiming in the right direction, or if I am still not approaching this quite right.
Here is what I think might work (although, it seems a bit too easy):
Use local variables per page.
In an (IsPost) branch assign the session variables based off of the local variables just before posting/redirecting.
On the other page, just after being redirected, use the session variables to assign new static local variables.
In other words: I will (when necessary) use the session variables only to transfer the data which will happen in a completely acceptable amount of time (not allowing the session state enough time to timeout), and then referring only to the local variables when needed, per page.
Am I crazy or is this the best way (or at least a decently viable way) to handle this, when forced to work with the session state in WebMatrix?
Sorry if this is a stupid question xD
In my opinion, you should not use Session variables to remember what the user entered into the form. The form - add or edit - should post to itself for validation. That way, the values are available in the Request.Form collection. You can easily repopulate the form in the event of a validation error. On successful submission, you insert or update the database, and then redirect to another page to prevent duplicate submission.
Session variables are really easy to use if used appropriately. I suspect your difficulties arise because you are using them for the wrong scenarios.
Is it a good idea to avoid state management techniques(session, cookies etc) in ASP.Net MVC 3.0?
If yes then is there any other alternatives available except TempData?
This would depend on your specific requirements. Session state and cookies for example are very different beasts.
If session state is a good fit to your requirements in WebForms then it's a good fit in MVC. There is no specific reason not to use it in MVC.
You basically only have 3 places you can store data, on the client (cookies/hidden values/query string), on the server (session/cache/static), in the database.
There is loads of documentation of the pros and cons of all these methods, a good starting place is:
http://msdn.microsoft.com/en-us/library/z1hkazw7.aspx
It depends.
Session and cookies were invented to solve some kind of problem, so they should be used to solve that problem.
TempData won't help much in replacing cookies - because cookies are saved on client side.
Also TempData is Session, distinction is that TempData is for redirection only. As long as TempData is quite usefull in redirection scenarios, you may wish to keep session to be enabled for these scenarios.
If you don't have session oriented scenarios (like object creation has multiple steps and after first step you can't save it to database yet), you can avoid using it, but in general it is not by itself evil.
I find that state is nicely maintained in a cache when implementing the repository pattern. In the MVC Futures project, there is also the Html.Serialize method which gives 'view state like' state storage.
http://mvccontrib.codeplex.com/
For information like items bound to a combobox that we were used to having maintained automatically for us in web forms, a good alternative here is to call off to a repository for the data. The repository maintains a reference to a cache (ideally through an interface you create like - ICache). The repository then caches this data based on for ex. the current users name, key whatever. Some prefer to have a service layer cache, but I feel by design a repository layer was meant for this.
Session is still used - if you must - it has its place. A lot of 'bad' surrounds the session, but if you need to store session specific information and your site isn't concerned with a large number of hits a day, then you can likely take the hit just fine.
TempData is great for storing status messages to show on the next request such as 'record saved successfully' so you don't lose it across the redirect and don't have to pass it on the querystring. Thats about the only thing I use it for although some use it to store data for rebinding on the next request.
IMO, the rules for session state in MVC are the same as the rules in WebForms: use it if you must, but keep your usage lightweight. If you truly have some data to track per user/session, there is no need to reinvent the wheel.
You can save your state in the database directly
I'm building a web system and various clients will have alternate text for default instances throughout the site. One place is the main nav but there are others. The default may be "project" but they may want to call it "event".
I'm heading down the road of calling all the terminology settings (there's a list of about 15) and creating an ArrayList that has the id and either the default or their replacement as the items in the ArrayList.
I've also got a enum key list called TermKey that has the defaults and the corresponding ID number.
Throughout the code I'll reference TermKey.Project and then do one of these things that I see as options.
1-pull the text from the session (if the client has set it to "event" then the text "event" will be waiting for the call there)
2-pull the text from the database every time I need it.
3-pull the client's list each time a page loads.
Some thoughts on the impact each way or if there is a best practice for this sort of thing would be appreciated.
The session isn't the best place for this kind of information. While yes, it is user-bound, the session state is really a repository for user-bound, session-bound information. What you seem to have is information that really has a scope beyond session.
The best way to reflect this information is to use a custom ASP.NET Profile Provider. You would use it to expose properties for the information you need to expose, while the logic in the properties would handle setting the values to the appropriate values based on the user in your system (or, an anonymous user, if they are not authenticated).
In your case, you could cache the values and access the database as needed in the profile provider.
Then, this information is exposed through the Profile property on the HttpContext class (and through the Profile property on the HttpProfileBase class as well if you are using ASP.NET MVC).
Anyway you shouldn't call DB on every page just to get alternate text. I think it is fine to store them in session if there are not too many of them (per user)
The way I've done this in the past is to have a database type code table and then a client-specific translation table like this:
TABLE ObjectType
ObjectTypeCode
TABLE ClientObjectTypeTranslation
ClientId
ObjectTypeCode
OverrideDescription
This allows my code to always reference what I know (i.e. ObjectTypeCode) and I then join to the translation table on every query and display the override description where relevant.
Though, this may be overkill for your scenario.
Session is ok to do this if you want to persist across sessions (and it's not TOO much data). Another option would be cookies.
I'd recommend on session start, instantiate session vars in a User object property, then can reference, User.DefaultText
If this is specific to each user, you might as well use session. Don't overuse is (and only use it for small amounts of data).
Going to the database for each request can be overkill, especially if this data doesn't change often - it will be much faster to retrieve from local memory than from over the network.
Having said that, using session InProc will limit you to a single server and will not allow you to scale to a web farm.
I have a multi-user ASP.NET MVC application. The users are not supposed to see or do anything with each other's data.
One of my controller actions is the obligatory POST to /Edit to edit a record (e.g. a contact). Now here is my problem: What if somebody forges a simple POST to /Edit (which automatically model-binds to my contact class) and edits somebody else's information? As each record is identified by Id, all that would have to be done is make a fake POST with Id XXX and then record # XXX would be overwritten with whatever the attacker supplied. How can I stop this?
The only thing I thought of is fetching the original instance every time first from the DB, check that it is in fact within the user's scope of editable objects (the ones he'd usually see to edit) and only if that check passes to proceed with UpdateModel and committing the update changes.
Is there a better way?
Edit: This is not a Cross Site/CSRF attack. Another logged in user can do this.
Authorization for the view/page and authorization for the particular object are really two separate concepts. The best approach is problem to use an Authorize attribute in conjunction with the ASP.NET roles system to either grant or deny access to a given page. Once you have verified that the user has access to the page, then you can verify whether he has the permission he is requesting for the object on which he is requesting it. I use this approach in my application, and it works great. By using the Authorize filter first, it significantly improves performance since the actual object permission checking is a much heavier operation.
Also, I use a home brewed rules system to actually set and determine whether the user has access to the object. For example, in my system, administrators have full access to every object. (That's a rule.) The user who creates the objects has full access to the object (also specified by a rule). Additionally, a user's manager has full access to every thing his employees have access to (again specified by a rule.) My application then evaluates the object to see if any of the rules apply--starting with the lest complex rules first and then moving on to the more complex rules last. If any rule is positive, I discontinue rule evaluation and exit the function.
What you could do is exclude the ID in the model binding with this syntax:
public ActionResult Edit([Bind(Exclude="Id")] User userToEdit)
and then fetch the ID from the current logged in user instead, so that it is only the logged in user that can edit his own items and noone elses.
Loading the original record first and checking the owner sounds like a good approach to me. Alternatively you could add a hidden field containing the record ID and cryptrographically sign that field to make sure it can't be changed, or take the record ID, hash it using the user ID as a salt and check that (assuming you're using the membership providers you should use the provider unique ID, not the login name)
This question reminded me of an article that covers a similar issue (in light of URL manipulation attacks) that i had bookmarked. They deal with an authenticated user messing with the data of another user. You might find it useful:
link text
Edit: This link should be correct:
Prevent URL manipulation attacks