I am trying to find a good pattern to use for user access validation.
Basically on a webforms application I had a framework which used user roles to define access, ie, users were assigned into roles, and "pages" were granted access to a page. I had a table in the database with all the pages listed in it. Pages could have child pages that got their access inherited from the parent.
When defining access, I assigned the roles access to the pages. Users in the role then had access to the pages. It is fairly simple to manage as well. The way I implemented this was on a base class that every page inherited. On pageload/init I would check the page url and validate access and act appropriately.
However I am now working on a MVC application and need to implement something similar, however I can't find a good way to make my previous solution work. Purely because I don't have static pages as url paths. Also I am not sure how best to approach this as I now have controllers rather then aspx pages.
I have looked at the MVCSitemapprovider, but that does not work off a database, it needs a sitemap file. I need control of changing user persmissions on the fly.
Any thoughts/suggestions/pointers would be greatly appreciated.
When you create an MVC application, not the blank website, there is a basic ASP.NET Membership provider included. That will do everything you are looking for, with little to no coding.
Here is MSDN: http://msdn.microsoft.com/en-us/library/yh26yfzy.aspx
Here is a CodePlex project that expands the functionality more than what was built in: http://mvcmembership.codeplex.com/
Your technique is easily accomplished by creating your own ActionFilter:
http://msdn.microsoft.com/en-us/library/dd410056.aspx
You can then apply this attribute to controllers or action methods and roll your own page security very easily.
public class MinmalSecurity : ActionFilterAttribute
{
private string _roles;
public MinmalSecurity(string roles)
{
_roles = roles;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//go to database,find permissions, redirect or proceed as nescessary
base.OnActionExecuting(filterContext);
}
}
Related
There is an ASP.NET 2.0 web site that I intend to migrate to a new web framework based on ASP.NET 4.0. While I know this involves manually preparing a script/program to transform site's content from old application's database schema to the new one, I am more concerned about preserving the old URL formats; mapping them to the new web engine's URL format.
I have not yet decided what is the most appropriate CMS engine to migrate towards (thus Web forms or MVC is still not clear). However, I'd like to draw on everybody's experience on
general issues to look out for (regardless of web application platform)
candidate strategies/techniques to handle the URL remapping in ASP.NET
Google Analytics is already configured for the web site, so there is a history of the most requested links to study - which are the most important URL formats to remap and which are not worth preserving.
Due to work areas i've been diverted to the past few years, I've not been able to keep up with the latest ASP.NET capabilities that can help with this. Oddly, I find little material discussing how to properly preserve old URLs; most web sites are pretty nasty in totally discarding their old links when they perform a design overhaul.
My first thought of the most straightforward technique is just to specify in web.config a custom 404 aspx page that will read the old requested URL (which will carry the original content ID). Based on the content ID, look up a custom database table to find the new content ID, and redirect with the new URL.
At this point I am unsure if I'd want to make use of URL rewriting HttpModule or extension because I'd only want to incur the "lookup" only when it becomes 404, rather than a check on each and every request. Knowing that old URL requests will eventually fade over time.
What other factors/aspects should I consider?
For SEO performance, it's not really a good idea to issue a 404 or a 302 if you want to maintain good link value for each page you should issue a 301, a permanent redirect which search engines will use to pass any link equity to the new url.
With MVC you could register your old urls to a route that uses some form of dedicated RedirectController, something like:
public class RedirectController : Controller
{
public ActionResult RedirectArticle(int articleId)
{
string newUrl = // do something to figure out the new url, e.g. http://localhost/article/1 -> http://localhost/1/my-custom-article-url
return RedirectPermanent(newUrl);
}
}
That way, you can register routes to support both the old infrastructure and the new, with a RedirectController issuing the appropriate page-specific 301 redirect to the new page.
routes.MapRoute(
"NewArticleUrl",
"/{articleId}/{articleTitle}",
new { controller = "Article", action = "Display");
routes.MapRoute(
"OldArticleUrl",
"/article/{articleId}.aspx",
new { controller = "Redirect", action = "RedirectArtciel" });
Microsoft has a new website editing tool: WebMatrix. WebMatrix uses the new Web Pages engine in which Razor is the view engine; Razor is also the new view engine for MVC3. I am attempting to find out if it is possible to register and use a different view engine in Web Pages (like you can in MVC).
Does anyone know if it is possible to add or replace the view engine in Web Pages? If so has anyone documented this? Examples?
I'm hoping to try this myself a bit later, but for now I'll just share my current thoughts:
In WebPages, Razor works by registering a BuildProvider with the ASP.NET build pipe for .cshtml and .vbhtml.
WebPages, in turn, registers the .cshtml .vbhtml extensions to its handler.
When a webPages page is requested, System.Web.WebPages.WebPageHttpHandler passes the path to the build pipe, where the extensions are matched with the registered Razor Provider, which renders the page and passes back a WebPage object, which handler passes to IIS and is served up.
You'll see all this if you use a reflection tool. Both of these are achieved in the PreApplicationStartCode.Start() of the corresponding assembly.
Razor hooking its build provider:
public static void Start()
{
if (!_startWasCalled)
{
_startWasCalled = true;
BuildProvider.RegisterBuildProvider(".cshtml", typeof(RazorBuildProvider));
BuildProvider.RegisterBuildProvider(".vbhtml", typeof(RazorBuildProvider));
}
}
WebPages hooking the WebPageHandler
public static void Start()
{
if (!_startWasCalled)
{
_startWasCalled = true;
WebPageHttpHandler.RegisterExtension("cshtml");
WebPageHttpHandler.RegisterExtension("vbhtml");
PageParser.EnableLongStringsAsResources = false;
DynamicModuleUtility.RegisterModule(typeof(WebPageHttpModule));
ScopeStorage.CurrentProvider = new AspNetRequestScopeStorageProvider();
}
}
To override we'd need to create and register a separate BuildProvider with the ASP.NET pipe to render our pages. System.Web.WebPages provides a WebPageHttpHandler.RegisterExtension() method which in theory you can hook a different BuildProvider to which will get the WebPage request instead of Razor.
Several blogs mention the RegisterExtension method, but there is also an open connect bug report showing it doesn't work 100%. It may be more appropriate to just override everything and hook our buildprovider to the pipe (not using the method).
Web.config provides a construct to register buildProviders, so I'll prob try that.
<buildProviders>
<add extension=".cshtml" type="CustomStuff.CustomBuildProvider"/>
</buildProviders>
The challenge is that most of the view engines out there use ViewEngines.Register(), a concept that webPages does not appear to have. So we'd have to wrap those view engines in a BuildProvider and/or create a BuildProvider that can successfully invoke IViewEngine
Again, just sharing my thinking. I'll try to register Spark or something later if I find some time.
You can't "register" view engines in Web Pages in the same way as MVC. You just mix and match file types. There's nothing to stop you adding .aspx files to your Web Pages site. Web Pages is much more akin to a Web Site project in VS.
Is it possible to require the user be authenticated (logged in) when downloading ZIP files from my site? Note that I don't have direct control of IIS7. (I'm on a shared hosting account.)
I can't simply alter the access for a particular directory because many directories are involved and most contain other files that can be accessed freely.
I've Googled this a bit and found similar questions. But I've been unable to find this exact question.
EDIT: This is specifically a programming question (even if the answer is that it can't be accomplished via programming). Also, it asks a very specific question. (Apparently, a couple of people were confused on these points.)
Why not use forms authentication? You could then simply check for a valid auth cookie.
In MVC, my solution was to create a controller to handle the downloads, and apply the [Authorize] attribute to that controller so, with a route like:
downloads/get/{filename}
and a controller action:
[Authorize]
[HttpGet]
public ActionResult Get(string fileName)
{
// should pull this path from web.config or a database...
string downloadFolder=#"c:\inetpub\virt\downloads\";
// FileResult() renders the binary content of the specified file back to the browser.
return(new FileResult(Server.MapPath(downloadFolder+fileName), " application/zip"));
}
If you're using webforms, there are a couple of different ways to handle it using either an ASPX or ASHX. But, they all come down to the same idea:
Parse the url to get the download file name.
Find and load the file contents from disk
Set the content-disposition header in the response to tell the browser what the filename should be
Response.BinaryWrite() the binary data back to the browser.
Here's an OLD example article using an ASHX.
This should fix your problem: since the requests are going through ASP, and not just direct to the ZIP or other files, the requests have to pass through whatever authentication system you're using. (Forms authentication works fine and does solve this problem.)
Update
Here's a nice link on MSDN that works in webforms.
Here's how I resolved this:
I created a custom HttpHandler for ZIP files. What's really cool with IIS7 is that you can map a file to your handler in the new <httpHandlers> section of the web.config file.
The HttpHandler object receives an HttpContext object, which includes User.Identity.IsAuthenticated already filled out for me. I simply pass along the requested file if the user is authenticated, or redirect them to my login page if not.
With older versions of IIS and ASP.NET, it would be necessary to tweak IIS to map ZIP files to ASP.NET. However, IIS and ASP.NET are merging somewhat, making tasks like this much easier.
I would suggest contacting your hosting provider. Many shared hosting providers give you access to your .htaccess file or some means of securing your site. This would be different from provider to provider.
I'm doing some research on security and sitemaps in ASP.net and am unfortunately running short on time. I have not worked too much with ASP.net security so I'm not completely sure if I'm heading in the right direction.
Here is my problem:
I have a public website (i.e. on the internet) that will allow any user to sign up to. The website will be developed using ASP.net webforms. These users may create other users and assign these users different roles.
Different roles have different restrictions and the menu is displayed appropriately. For example, a user acting as an administrator can see all menu options. Whereas a limited user will only see some of these menu items.
There needs to be the ability for users on our end to modify what pages certain roles can access. For example, if Role1 can do task X, we would like to be able at some point modify Role1 to no longer do task X. This would be done using an application built in-house.
User types (roles) are to be saved in the database. User permissions (what pages each type can have access to) are also to be saved saved in the database.
Here is something I am thinking of doing:
Implement the authorization and authentication set up built in to ASP.net using the web.config file
Use Sitemaps to dynamically create menus/breadcrumbs from the database
I believe it is possible to do the second one using custom providers (please correct me if I'm wrong). But I am not entirely sure if it's possible to configure the web.config file dynamically.
I suppose this is really more of a yes/no answer but I would just like to make sure I'm not going in the wrong direction. I will be using VS2008 and .net 3.5 framework.
Many thanks.
Yes, it's possible to do what you're saying. You can dynamically create the sitemaps using a custom SiteMapProvider, see this articlet http://www.codeproject.com/KB/aspnet/dynamicsitemap.aspx.
You can also modify the web.config at runtime using an XmlReader or if you prefer, just reading it into a string and parsing out the authorization element. I'd put it in a separate file, though, using configSource:
<authorization configSource="auth.config" />
Then you only need to modify that file and not worry about messing up the web.config
Here is my desired flow:
A static web page (html) uses XHR calls to an ASP.NET page
The .NET page retrieves information from a remote server using web services
The .NET page returns an HTML "snippet" that is inserted into the static HTML page
I'm getting hung up on how to deal with the HTML snippet generation on the .NET (2.0) page. I've thought about something like this in a generic .ashx page:
public void ProcessRequest (HttpContext context)
{
context.Response.Write("<ul>");
//assume "people" is a list of data coming from the external web service
foreach (string person in people)
{
context.Response.Write("<li>" + person + "</li>");
}
context.Response.Write("</ul>");
}
It just seems a big "ugly". Has anyone done this another - and possibly more efficient/elegant - way? Any help would be appreciated.
Returning html for this task is a bit weird, IMO. In most times I prefer the following way. Open your web service to public or add a wrapper to it and just use it directly from js of your static page. The service should return json (preferable) or xml data. On the client side format (print in html as you want) received data using js in callback to the XHR and inject anywhere you want.
But also I want to cast YAGNI on this task - if it'll be used only several times and in a few pages, use the most fastest way to implement it. But if you are building some RIA application I recommend you to check ExtJS javascript library.
Edit 26/02:
If you can't use ASP.NET MVC but wanna to use some good framework instead of "Response.Write" stuff please check OpenRasta. It's one of my favorite web frameworks. It works fine on .Net 2.0 and it's very flexible and powerful. And also it has a great community.