asp.net mvc and portal like functionality - asp.net-mvc

fHi,
I need to build an site with some portal like functionality where an param in the request will indentify the portal. like so http:/domain/controller/action/portal
Now my problem is if an portal doesn't exists there must be an redirect to an other site/page and an user can login in to one portal but if the user comes to an other portal the user must be redirected back to the login page for that portal.
I have something working now, but i feel like there must be an central place in the pipeline to handle this. My current solution uses an custom action filter which checks the portal param and sees if the portal exists and checks if the user logged on in that portal (the portal the user logged on for is in the authentication cookie). I make my own IIndentiy and IPrincipal in the application_postauthentication event.
I have 2 problems with my current approach:
1: It's not really enforced, i have to add the attributes to all controllers and/or actions.
2: The isauthenticated on an user isn't really working, i would like that to work. But for that i need to have access to the params of the route when i create my IPrincipal/IIndenty and i can't seem to find an correct place to do that.
Hope someone can give me some pointers,
Richard.

There's a couple different ways you could do this (as always...). If you want to do it in the controller (or via an attribute) but you also want to do it globally, then you could always use a custom base controller class and apply the logic there. The actionfilterattribute is inherited and bob's your uncle.
ON the other hand, this really feels like a routing concern to me. So I'd probably consider creating a custom route to handle what you're doing. If you do that, then once you get it working you'll want to test it out under load to make sure that you have a good caching strategy in place (so that every request isn't a db lookup for the route + another one for whatever happens in the controller).

You can enforce user authorization through an attribute in the controller. You would apply this to each action (both get and post). I think it's reasonable to add some sort of validation to each action within the controller to write secure code, please correct me if I'm wrong here.

For the missing portal redirect, I would handle this in routing. If you have a relatively small number of portals, you can do this by creating a unique route for each of your controllers and then setting a default route for the redirect. Routes are evaluated in the order you create them, so just put the default route at the bottom. Your route registration would look something like this:
routes.MapRoute(
"Portal1",
"{controller}/{action}/FirstPortal",
new {controller = "defaultController", action = "defaultAction",
portal = "FirstPortal"}
);
routes.MapRoute(
"Portal2",
"{controller}/{action}/SecondPortal",
new {controller = "defaultController", action = "defaultAction",
portal = "SecondPortal"}
);
routes.MapRoute(
"Default",
"{controller}/{action}",
new {controller = "defaultController", action = "defaultAction",
portal = "Default"}
);
This way you can use the "portal" route value to select the portal, and any request that does not match will be routed to the controller/action specified in your Default route, which can take care of redirecting the user appropriately.

Related

How to go to account controller if 5 level of product hierarchy is defined in product controller

I have used attribute routing for creating a hierarchy like following.
abc.com/Electronics/Audio/Portable Audio/iPods/Apple iPod Nano
Last one is the name of the product. This is defined in product controller.
Now I want to go to account controller on register link click but I can't go there as any level of route is caught in above URL criteria and it always goes to product controller methods.
So my question is , how can I go to account controller on click of Register link click. The register link is defined in Layout.cshtml.
Thank You
Keep in mind that you do set the order by virtue of the timing of your call, i.e. when you register the route attributes in relation to when you define the default route pattern. If you like, you can set the order of a RouteAttribute using the optional Order parameter.
[Route("controller/action", Order = 1)]
You may also wish to look at producing a LocalRoute that doesn't interfere with the default route routing, specifically for your complex product routing requirements:
Jon Galloway's walk through on custom constraints.
Solved it. Just put the route before attribute routing. For example
routes.MapRoute(
name: "AccountRoute",
url: "Account/Register",
defaults: new { controller = "Account", action = "Register"}
);
routes.MapMvcAttributeRoutes();
And you can go to your desired controller. Can't believe it was that simple. I still think that there are more effective ways to do that.
Thanx mahlatse & MisterJames

ASP.Net MVC: Check if URL is Authorized

I'd like to simply check from a Controller whether another URL is authorized.
So for example, I'd like to call into a Controller like so:
[HttpPost]
public ActionResult IsUrlAuthorized(string url)
{
bool isAuthorized = // What do I put here?
return Json(isAuthorized);
}
So I'd like to know what I could call to check on whether the current user is authorized for the passed-in URL or not. I'm guessing the answer has something to do with Routes, which sit a little bit outside MVC?
This is a somewhat similar question but not quite the same thing:
ASP.NET MVC. Check if user is authorized from JavaScript
Since the user may or may not be authorized in general, but may not have the right permissions or role assignments to see a specific URL.
Ideas?
Update: I use standard MVC authorization attributes to lock down my app, so I'll just give an example of what that looks like here. In MVC Routes map to Controllers. A single method on a Controller can be restricted to one or more Roles:
public class HomeController : Controller
{
[Authorize(Roles = "User, Moderator")]
public ActionResult ListRecentPosts()
{
. . .
}
}
Or, an entire Controller can be restricted to one or more roles:
[Authorize(Roles = "Admin")]
public class AdminController : Controller
. . .
The actual URL that any of these controller methods responds to is based on a default mapping in a standard MVC app:
routes.MapRoute("Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
But, you can be nice to your users and make URLs guessable by adding a lot more Routes - as a result, a Controller method can have many names that point to it. You can't just assume and infer the controller name from the URL (even if it maps out that way for half the URLs in the site).
So presumably I either need a way to ask the Routing engine directly whether a URL is authorized for the current user, or a 2-step of asking the Routing engine for which Controller and Method, then ask if those are authorized - hopefully not by using Reflection and matching Roles directly as that again would appear to assume too much.
Update 2: The way this came up is I have an Account strip at the top of my app. Its state can change by selecting one of several accounts you're authorized as. Depending on where you are in the app, the account you chose might have authorization to view this page - and you might be in the middle of filling out a form you don't want to lose. So the naive approach - just refresh when they pick another account - is harmful, and a waste of the user's time even if there is no form and they're just reading a page that's all text.
While that convenience to the user is nice, the user is going to fairly assume that pages they can't see as a user who shouldn't have permission really are denied (and, it would be harmful to leave them on a page that's forbidden - actions taken from it will fail). So I need to know whether to redirect away based on their new permissions.
One of the things I love about .Net is the way many of its best libraries decompose so well, so you can easily recompose things that are part of its normal functionality, or a new twist. Both the Routing module and MVC appear to be very well constructed, so I have to suspect this can be done.
The cheap hack is to ensure that my authorization module returns a consistent redirect status code when a user isn't authorized, and when the user changes their account in the account strip, fire 2 AJAX calls: One to change account, and then a second to the current page over AJAX just to check the HTTP Status Code. 200 OK means leave the page as is, Redirect means follow the redirect. Obviously this is a little ugly, involves an extra HTTP call, creates a false hit in the logs, and makes an assumption about how authorization is handled across the app.
There could be a secondary concern - the page might be authorized, but just change how it works or looks. This particular app has no change in look based on account (besides the account strip itself), and I can handle functionality changes by just providing a custom event that forms listen to - they can reload any relevant data from the server in response to it.
Using UrlAuthorization.CheckUrlAccessForPrincipal only works if you're only using URL authorization. But for MVC using Routing, we highly recommend that you don't use URL authorization to secure an app.
Instead, we recommend using Authorization attributes on the controller class. The reason is there could be multiple URLs that call the same controller action. It's always better to secure the resource at the the resource and not just at the entry ways.
In this particular case, you'd have to get an instance of the controller given the URL. THat's a little tricky as you'll basically have to run the MVC pipeline from the point where you have the URL to the point where you have the controller. It's possible, but seems heavyweight.
I wonder if there isn't a better and simpler way to accomplish your goals. What is it you're really trying to do?
UPDATE: Based on your scenario, it sounds like this is an initial check just for UI purposes. Perhaps all you need to do is make an asynchronous Ajax request to the URL and check the HTTP Status code. If it's a 401 status code, you know the user is not authorized. That seems like the safest bet.
How about UrlAuthorizationModule.CheckUrlAccessForPrincipal method.
UrlAuthorizationModule.CheckUrlAccessForPrincipal Method (System.Web.Security)

object oriented url scheme in asp.net mvc 2

I'd like to modify the standard ASP.NET MVC URL routes
http://example.com/Controller/Action[/Id]
to something like:
http://example.com/Controller/Id/Action
Modifying the route scheme is trivial but I'm getting into trouble when handling default values. I would need these URLs
http://example.com/Controller/ -> Maps to Index() -> List of items
http://example.com/Controller/Create
http://example.com/Controller/Id[/Details] -> Maps to Details(id)
http://example.com/Controller/Id/Edit -> Maps to Edit(id)
http://example.com/Controller/Id/Delete -> Maps to Delete(id)
Yikes! This means quite a few routes instead of the nice default one. Or can I use URL parameters with default values in the middle of the URL?
The next step is to use a friendly (yet unique!) object reference (eg customer name. Let's assume it is unique) instead of a DB record identity (id). Such as:
http://example.com/Controller/Name[/Details] -> Maps to Details(id)
So far so good but I'm not sure it's a good idea to use this for the Edit (and possibly delete) page: The edit form lets user modify the object name, leading to possible mismatches in url. Should I stick to the id in Edit URLs?
Did anyone experience with such URLs? Did you push the idea to hierarchical systems? Is this all a good idea or will I dive into more trouble than benefits?
TIA for your thoughts.
You can do this only if the ID parameter is always present in the URL. For obvious reasons optional parameter can only be at the end of the url or it is impossible to disambiguate them.
Try this:
routes.MapRoute(
"Default", // Route name
"{controller}/{id}/{action}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Controller goes to home by default and will fire up the Index action of not said other wise. Id is as well optional. All I actually changed was the order of parameters.
As for the res of the question. If you're users are logged and they edit their profile for example you could get the Id of what to edit from somewhere else - a cookie for example. I do this in my user management. URL /User/Edit is unique for the user that's logged in.

Asp.Net MVC Default Route

I have my default route defined like this
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
However if the user is logged in when they visit the site (This can happen if they ticked the remember me button last time the logged in) I want them to take a different default route and go straight to the logged in page.
Is this possible in global.asax or will I need to put some logic in my home controller to redirect if logged in?
Best to put this in the home controller. A check if authenticated and return the appropriate view.
I want them to take a different default routeRouting in ASP.NET MVC is about routing URLs to action methods on controllers, not about routing users to places in your web site depending on the current circumstances. (Think of routing as a static thing, whereas the rest (authorization, redirection, etc) is only applicable to the current session.)
It is possible to use Routing Constraints to achieve what you want, but I don't think that's what you want.

ASP.NET MVC Default route?

I created a new ASP.NET MVC project and implemented a site authorization filter.
When I map the routes to the {controller}/{action} pair, I pass a role = "SomeRole" default to the route.
It works perfectly if I go through the full url (http://localhost/somecontroller/someaction) and I specified the full route
MapRoute("SomeAction", "somecontroller/someaction",
new { controller = "SomeController", action = "SomeAction", role = "SomeRole");
The problem is that when somebody visits http://thesiteaddress.com there has to be a default route that invokes /home/index instead of / and if I specify
MapRoute("Default", new { controller="somecontroller",action="action" });
then I lose the role="SomeRole" from the previous MapRoute.
How can I solve this?
Make sure the Default route is at the BOTTOM of your listed route table. Order matters when it comes to ASP.NET MVC Routing tables.
The correct ordering is your 'most specific' route to your least specific route.
Actually, George is right. MVC Routing respect ordering route. Your last route must be generic as possible, and your previous route must be specific as possible.
In your case, both are generic. You should
MapRoute("SomeAction", "Post/{action}", new {controller = "Post", role = "User");
and then
MapRoute("Default", new {controller="Home", action="Index", role = "Anonymous"});
so, you give specificity to both routes.
Phil Haack released a route debugging tool that can be invaluable in gaining an understanding of problems like this.
With this tool you can view how your MVC application parses a URL and matches it to your RouteTable.
When you don't provide the route name or the action is determined through a HTTP request it will look in order from the order they were added. The first time it finds one that matches, it stops. So what's probably happening is it's matching one previous to the one you've added.

Resources