I have a controller called Account and an action called AddFunds()
In my HttpGet Addfunds() action I return the view bind to a ViewModel with a AccountId property, so by default the view contains a hidden field called AccountId.
In the HttpPost AddFunds() action, I received the updated ViewModel, with the same AccountID as passed by the HttpGet method, with some other parameters, such as Amount, etc.
What can I do to prevent a person to invoke the method directly passing a fake AccountId?
Does the AntiForgery token prevent this?
Any other measure should I take?
As a side question, does passing the AccountID in a hidden field can be avoided or is it necessary to know which entity I am acting upon?
Thanks
First thing - you should really avoid using hidden fields for data/IDs, which are about to be passed to the controller's action and represent some real and possibly important data.
If you are concerned about user, who is given the possibility to manipulate ID you should either introduce not deterministic ID(like GUID).
Anti-forgery token is used to prevent performing CSRF attack.
You can encrypt the Id when you passing the value to post action and decrypt that id in the post method wherever it required.
your url will be : localhost:3040/home/edit?AccountId=hkdshjlk89890-32(encryptedid)
Or you can use base64 encode and decode(I won't recommend base64 because as every one decode the value).
Other solution you can see the below link
Only allow access to action if redirected from specific action
Related
Currently, our application has a lot of ActionLinks that only pass an id to the controller, where the object is retrieved again (that was already present/known on the previous page). Is there any cleaner way to do this, like pass the object instead? As our backend isn't too quick it takes a few seconds to load in the popup which you get after you click on the ActionLink.
I've seen some solutions using ajax to post the object but that doesn't seem like the neatest solution to paste those js lines under/at every ActionLink that is used in combination with a popup.
The #Html.ActionLink() method will generate a url link to the given Controller/Action. Thus, it can only contain parameters that can be contained in the url of the link. So you cannot pass an object through on the url.
If you need to pass through the reference to an object that is stored on the server, then try setting a parameter of the link to give a reference to the object stored on the server, that can then be retrieved by the action (example, the Id of the menuItem in question).
Parameters in the ActionLink are set through the collection that you passed in as the third item in your function call above. Assuming default routing, this would give an address that looks like /Admin/EditPage/?name=XXX where XXX is the value of menuitem.Title. If you included something else here like itemId = menuitem.Id then it would add this as a query string parameter to the url generated, which would then be accessible to the action that is the target of this link.
I'm developing a large ASP.NET Core 2 web application but I still get confused with URLs.
When fist learning, I thought URL's took on the name of the View, but discovered they come from the Controller method.
Here is an example to convey my issue:
I have a controller method named Daysheet, which returns a view and model with the same name.
In the Daysheet view, I call various controller methods from Javascript to perform specific actions. One of them is called AssignStaff which takes two integer parameters.
In the AssignStaff method I again return the Daysheet view with model, but now my URL is "AssignStaff"!
I can't just do a redirect because the whole Daysheet model is not being passed to the AssignStaff method.
I have many situations like this where after calling an action, I end up with another URL that I don't want.
UPDATE/EDIT
Thanks for assistance and apologies if my explanation is confusing. I simply have a view called Daysheet that uses a model. I want to call various controller methods to perform various actions, but I want to stay on the "Daysheet" view/URL.
As mentioned, I can't just redirect because in the action method I no longer have the whole model from the Daysheet view. Also, if I redirect I can't pass the whole model because that causes an error saying the header is too long. I think my only choice may be to use ajax for the actions so that the URL doesn't change.
When you just do Return View("") name in a Controller Action, the URL will be the name of the Action you are using.
If you want to redirect to some specific Action, that will help to make sure the Url matches to where you are. You might want to read more about it here.
To do so, use:
RedirectToAction()
The URLs your application responds to are called "routes", and they are either created by convention or explicitly. The default is by convention, of course, which is a URL in the form of /{controller=Home}/{action=Index}. Index is the default action if that portion of the route is left off, so a request to /foo will by convention map to FooController.Index. HomeController is the default controller, so an empty path (e.g. http://sample.com) will by convention invoke HomeController.Index.
Razor Pages have their own conventions. These do somewhat follow the file system, but exclude the Pages part of the path. So a Razor Page like Pages/Foo/MyRazorPage.cshtml, will load up under /Foo/MyRazorPage.
There there is the Route attribute, which allows you to specify a totally custom route. This attribute can be applied to a controller class and individual actions in the class. For example:
[Route("foo")]
public class MyAwesomeController
{
[Route("bar")]
public IActionResult MyAwesomeAction()
{
return View();
}
}
With that, a request to /foo/bar will actually invoke MyAwesomeController.MyAwesomeAction.
I'm creating a custom tree inside umbraco7 and and have a button which will call an UmbracoAuthorizedApiController called ExportApiController i added a constructor and set a breakpoint on it to see if this controller is indeed instanced and it is. But when i try to call the call my action it is returning an 405 (Method Not Allowed)
And in the response i see the following text
{"Message":"The requested resource does not support http method 'GET'."}
above my controller action i have the HttpGet attribute and i also tried the put or post but nothing helps. But i think that when i use post i need to do something else inside Angular to call it using a submit on a form? But i'm not sure how or why.
If you need more information please tell me and i will post it.
Thanks.
I had the same problem and for me the problem was that I accidently had HttpGetAttribute.HttpGet instead of System.Web.Http.HttpGet.
What is the name of your method ? I find that if you don't actually have "get" in the front of the name it would throw out this error so
public string CorrectTime(string time) < -- would fail but
public string GetCorrectTime(string time) <-- would pass
Because you want to export data, I guess you are trying to use this controller for the big public. However, UmbracoAuthorizedApiController are only for back-end users as mentioned in the documentation. You should not use these to expose data outside the Umbraco back-end.
If you want to expose data, and you want to validate against the members (not users) you should prefix your UmbracoApiController with the MemberAuthorize attribute
I have a controller with several action methods requiring the same list of data from a certain database. Since most of the actions were going to need access to the list, I quickly populated a private member variable with necessary list of data items directly in the constructor of my controller.
All was well and good until the database went down and an exception was thrown in the constructor. Apparently, that circumvents the normal HandleError functionality.
My goal is for this exception to be caught and the user redirected to an error view.
What is the proper way to load the data for all actions?
Is it appropriate to put a database call in OnActionExecuting?
Is there some way to do decorate the specific actions with an attribute that loads the data?
Am I over-thinking it? (After all, I could just drop a private method in the controller and call it from each action requiring the data)
You could create the private method and have it populate your list (if it's not already populated) and then return the list. This way your only calling the method to populate it when it's needed the first time, and you take fragile code out of your controller's constructor. It's going to much easier to handle the exception in your action methods than elsewhere.
Controllers (as objects) are being instantiated for every request. Therefore, there is no need to optimize data within controller which would be "reused" in many actions (as Jeff Reddy suggested). Unless you call an action method explicitly from another action method (which is bad practice anyway).
Make a private method GetData() that gets data from database and call it in every action.
However, you probably do want to avoid expensive database round-trips that get the same data over and over, then consider using HttpRuntime.Cache. You could save data there on the first call to GetData() and retrieve it from cache on subsequent requests.
If you need the model inside all your controller actions you could define a custom model binder for a given model and overriding the BidModel method which will query the database and populate this model. Then your controller actions could take this model as action argument:
public ActionResult Foo(MyModel model)
{
...
}
public ActionResult Bar(MyModel model)
{
...
}
If you don't need the model inside each action but inside each view you could externalize it as a widget using the Html.RenderAction helper.
I'm trying to find a good way to handle the following scenario (I'm still kinda new to this):
A user can register through my site using an RPX/OpenId provider.
Step 1: The user authenticates through a provider. The provider returns a temporary token to one of my action methods.
Step 2: I use the token to grab the user's profile information and load a view which allows them to enter any missing required fields and optional fields.
I use 2 action methods in Step 2: One to handle the grabbing of information using the token. A second action which takes the authorization information and loads the missing/optional fields view.
I am passing the authorization info via TempData to the second action. The second action can handle validation so there's a chance I will need to hold on to the authorization object for more than just 1 request. I can't use the token to regenerate the authorization info because it's technically a one-use token, and it would be silly to regenerate the request since it is using network resources.
How could I persist the objects in my TempData for any subsequent requests to the same action, but remove the objects for any redirects? And since this may be a repeatable pattern in my application should I create a Filter to automatically handle this situation?
For example, I imagine a filter attribute which will merge TempData (if any) into ViewData - But how would I persist my data into future calls to the same action? Throw it into TempData again? And if I detect a redirect empty the TempData?
Thanks
I ended up re-adding the data to TempData if necessary. Since TempData does not allow you to add duplicate keys I created my own helper method to remove and then re-add the key:
public static void AddNew(this TempDataDictionary tempData, string key, object obj)
{
if ( tempData.ContainsKey( key ) ) tempData.Remove( key );
tempData.Add( key, obj );
}
I've had the same problem, but approached it a slightly different way - I've used a Forms Authentication method which works solely with OpenID... if my provider returns Authenticated, I do the following
var fields = openid.Response.GetExtension(typeof(ClaimsResponse)) as ClaimsResponse;
if (fields != null)
{
TempData["Email"] = fields.Email;
TempData["Nickname"] = fields.Nickname;
}
FormsAuthentication.RedirectFromLoginPage(openid.Response.ClaimedIdentifier, false);
break;
This means that I don't need to pass any kind of Authentication token around - after this code executes I know my user is authenticated.
Therefore, the action that this passes control to will simply copy the TempData fields, if populated, into ViewData and pass them onto the view.
Validation is handled after this - I don't care what comes back from OpenID (i.e. is it valid or not), I let the user edit this and then save, and then perform my validation.