How to disable direct access to a view from url? - asp.net-core

I have two views in my asp net core application. The first view is called customer and the second view is called payment. I want to disable that users can get direct acces by typing the url "https://mywebsite/Payment" in the browser.
I want the users to be redirected to view which is called customer If users are trying to get direct access to view called payment.
How can I do that. I don't have any idea.

You could create a filter as below :
public class NoDirectAccessAttribute:ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var canAccess = false;
//check the refer
var referer = context.HttpContext.Request.Headers["Referer"].ToString();
if(!string.IsNullOrEmpty(referer))
{
var request = context.HttpContext.Request;
var rUri = new System.UriBuilder(referer).Uri;
if(request.Host.Host==rUri.Host && request.Host.Port==rUri.Port && request.Scheme==rUri.Scheme)
{
canAccess = true;
}
}
// ... check other requirements
if (!canAccess)
{
context.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Home", action = "Index", area = "" }));
}
}
}
Then you can apply NoDirectAccess Attribute to specific Action
[NoDirectAccess]
public IActionResult Privacy()
{
return View();
}

Related

How to use fallback routing in asp.net core?

I am using asp.net web-api with controllers.
I want to do a user section where one can request the site's address with the username after it like example.com/username. The other, registered routes like about, support, etc. should have a higher priority, so if you enter example.com/about, the about page should go first and if no such about page exists, it checks whether a user with such name exists. I only have found a way for SPA fallback routing, however I do not use a SPA. Got it working manually in a middleware, however it is very complicated to change it.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
string[] internalRoutes = new string[] { "", "about", "support", "support/new-request", "login", "register" };
string[] userNames = new string[] { "username1", "username2", "username3" };
app.Use(async (context, next) =>
{
string path = context.Request.Path.ToString();
path = path.Remove(0, 1);
path = path.EndsWith("/") ? path[0..^1] : path;
foreach (string route in internalRoutes)
{
if (route == path)
{
await context.Response.WriteAsync($"Requested internal page '{path}'.");
return;
}
}
foreach (string userName in userNames)
{
if (userName == path)
{
await context.Response.WriteAsync($"Requested user profile '{path}'.");
return;
}
}
await context.Response.WriteAsync($"Requested unknown page '{path}'.");
return;
await next(context);
});
app.Run();
It's really straightforward with controllers and attribute routing.
First, add controller support with app.MapControllers(); (before app.Run()).
Then, declare your controller(s) with the appropriate routing. For simplicity, I added a single one that just returns simple strings.
public class MyController : ControllerBase
{
[HttpGet("/about")]
public IActionResult About()
{
return Ok("About");
}
[HttpGet("/support")]
public IActionResult Support()
{
return Ok("Support");
}
[HttpGet("/support/new-request")]
public IActionResult SupportNewRequest()
{
return Ok("New request support");
}
[HttpGet("/{username}")]
public IActionResult About([FromRoute] string username)
{
return Ok($"Hello, {username}");
}
}
The routing table will first check if there's an exact match (e.g. for /about or /support), and if not, if will try to find a route with matching parameters (e.g. /Métoule will match the /{username} route).

Redirecting to a response view with a model does not keep model properties

I have a form view that submits form data to the post action on a controler and then redirects to another view that uses logic to display either a success or failure, but the new view just shows blank values for model properties. Here is the post action:
[HttpPost]
public ActionResult ContactUs(TTT.Models.ContactUsModel model)
{
logger.Info(model.URL + "Contact Us Form submitted");
var userkey = model.ValidationKey;
var sessionkey = Session["ContactUsKey"];
var lastsubmission = Session["ContactUsTime"];
model.Response = "success";
//first check if honeypot was populated via a bot and if so send it to the success page without doing anything
if (model.WorkAddress != "")
{
logger.Info("honeypot triggered");
return View("ContactUsResponse", model);
}
I'll leave out the remainder of the controler, but
And here is the view it's redirecting to:
#using TTT.Models
#using Sitecore.Mvc
#model ContactUsModel
<h1>#Model.Title</h1>
<div>#Model.Body</div>
<div>
#if (#Model.Response == "fail")
{
#Model.Failure;
} else
{
#Model.Success;
}
</div>
Instead of returning a new view, call RedirectToAction and return new view from that controller.
[HttpPost]
public ActionResult ContactUs(TTT.Models.ContactUsModel model)
{
//--- Code omitted for brevity
if (model.WorkAddress != "")
{
logger.Info("honeypot triggered");
return RedirectToAction("ContactUsResponse", new { response = model });
}
}
public ActionResult ContactUsResponse(TTT.Models.ContactUsModel response)
{
return View(model)
}

Usage of UseStatusCodePagesWithReExecute with a message not working as expected

I'm using UseStatusCodePagesWithReExecute in my .NET Core 2.1 web app as follows
app.UseStatusCodePagesWithReExecute("/Error/{0}");
and in my Controller I point to 1 of 2 views, a 404.cshtml view and a generic error.cshtml view
public class ErrorController : Controller
{
[HttpGet("[controller]/{statusCode:int}")]
public IActionResult Error(int? statusCode = null)
{
if (statusCode.HasValue)
{
if (statusCode == (int)HttpStatusCode.NotFound)
{
return View(statusCode.ToString());
}
}
return View();
}
}
Now in my page controller I can do the following and it works as expected. It will show error.cshtml
public IActionResult SomePage()
{
return BadRequest();
}
Now if I change the above to the following, my ErrorController does get hit but by the time it does a blank view showing just "Some details" has been loaded in the browser.
public IActionResult SomePage()
{
return BadRequest("Some details");
}
Any ideas why? I want it to load error.cshtml
As #Kirk Larkin said , UseStatusCodePagesWithReExecute middleware won't work and it will only handle the status code .
You can use Result filters to write your custom logic to filter that and return a ViewResult :
public class StatusCodeResultFilter : IAsyncResultFilter
{
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
// retrieve a typed controller, so we can reuse its data
if (context.Controller is Controller controller)
{
// intercept the NotFoundObjectResult
if (context.Result is BadRequestObjectResult badRequestObject)
{
// set the model, or other view data
controller.ViewData.Model = badRequestObject.Value;
// replace the result by a view result
context.Result = new ViewResult()
{
StatusCode = 400,
ViewName = "Views/Error/status400.cshtml",
ViewData = controller.ViewData,
TempData = controller.TempData,
};
}
}
await next();
}
}
Register the filter :
services.AddMvc(config =>
{
config.Filters.Add(new StatusCodeResultFilter());
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
In your view , you can directly get the detail message by :
#Model
Reference : https://stackoverflow.com/a/51800917/5751404

How to keep data in ActionFilterAttribute after redirect

I am working on ASP.NET MVC 4 application. I've created custom filter which purpose is to call page which display loader image. The filter looks like this:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var useLoader = filterContext.RouteData.Values["ul"] as string;
if (string.IsNullOrWhiteSpace(useLoader))
{
var view = new ViewResult()
{
ViewName = "DisplayLoader"
};
view.ViewData.Model = filterContext.HttpContext.Request.Url.PathAndQuery;
view.TempData["ul"] = "1";
filterContext.Result = view;
}
}
In the DisplayLoader view I just do this:
#model string
<script type="text/javascript">window.location = '#Html.Raw(Model)';</script>
but the problem is that after the redirect the useLoader value is always null. Is there way to persist this data?

Redirect to action with parameters always null in mvc

When I tried redirect to action, the parameter is always null when I received ? I don't know why this happening like these.
ActionResult action1() {
if(ModelState.IsValid) {
// Here user object with updated data
redirectToAction("action2", new{ user = user });
}
return view(Model);
}
ActionResult action2(User user) {
// user object here always null when control comes to action 2
return view(user);
}
And with this I've another doubt. when I accessed action with route, i can get values only by RouteData.Values["Id"]. the values routed doesn't send to parameter.
<a href="#Url.RouteUrl("RouteToAction", new { Id = "454" }> </a>
Here Am I miss any configure ? or anything I miss.
ActionResult tempAction(Id) {
// Here Id always null or empty..
// I can get data only by RouteData.Values["Id"]
}
You cannot pass complex objects in an url like that. You will have to send its constituent parts:
public ActionResult Action1()
{
if (ModelState.IsValid)
{
// Here user object with updated data
return RedirectToAction("action2", new {
id = user.Id,
firstName = user.FirstName,
lastName = user.LastName,
...
});
}
return view(Model);
}
Also notice that I have added the return RedirectToAction instead of only calling RedirectToAction as shown in your code.
But a much better approach is to send only the id of the user:
public ActionResult Action1()
{
if (ModelState.IsValid)
{
// Here user object with updated data
return RedirectToAction("action2", new {
id = user.Id,
});
}
return view(Model);
}
and in your target action use this id to retrieve the user from wherever this user is stored (could be database or something):
public ActionResult Action2(int id)
{
User user = GetUserFromSomeWhere(id);
return view(user);
}
Some alternative approaches (but one I don't recommend or use) is to persist the object in TempData:
public ActionResult Action1()
{
if(ModelState.IsValid)
{
TempData["user"] = user;
// Here user object with updated data
return RedirectToAction("action2");
}
return view(Model);
}
and in your target action:
public ActionResult Action2()
{
User user = (User)TempData["user"];
return View(user);
}