Authorization denied message with FormsAuthentication
So, I've implemented my IPrincipal.IsInRole(...) and I'm using FormsAuthentication like so:
<authentication mode="Forms">
<forms loginUrl="Login.aspx" name="someName" timeout="600"/>
</authentication>
Then I have a page that requires you to be authenticated and that you have "roleA". This is configured like so:
<location path="SomePage.aspx">
<system.web>
<authorization>
<allow roles="roleA" />
<deny users="*"/>
</authorization>
</system.web>
</location>
Now, I login to my web application, but with a user that does NOT have roleA. When I visit SomePage.aspx I get redirected to Login.aspx, the url specified in loginUrl of the forms element. So, my question is shouldn't I be able be specify an authorization denied message or url? If the user is authenticated, but not authorized why would I want to red开发者_高级运维irect to the login page. It's confusing as hell to the user. Please tell me I am missing something simple.
Thanks for reading!
Yeah, this is a little annoying. Maybe someone has a simpler idea, but the solution (hack?) that we came up with was to look for the originally-requested URL that ASP.NET appends to the query string when the user is redirected to the login page.
We created a new web.config section that stores a set of keys/values that match a fragment of the redirect URL to an authorization message:
<configSections>
<section name="authorizationFailureMessages" type="System.Configuration.NameValueSectionHandler, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
...etc...
</configSections>
<authorizationFailureMessages>
<add key="MemberResources" value="MembershipRequired" />
<add key="Staff" value="StaffOnly" />
<add key="Departments/Administration/BoardOfDirectors" value="BoardOfDirectorsOnly" />
...etc...
</authorizationFailureMessages>
In the Page_Load() event of the Login.aspx page, we call a method that uses this URL to determine which (un)authorization event occurred then redirect them to a message page that displays the appropriate text:
private void DisplayAppropriateAuthorizationMessage ()
{
if ( !Page.User.Identity.IsAuthenticated )
return;
string redirectUrl = FormsAuthentication.GetRedirectUrl( Page.User.Identity.Name, false );
if ( string.IsNullOrEmpty( redirectUrl ) )
return;
NameValueCollection authorizationFailureMessages = ConfigurationManager.GetSection( "authorizationFailureMessages" ) as NameValueCollection;
if ( authorizationFailureMessages == null )
return;
foreach ( string key in authorizationFailureMessages.AllKeys )
{
if ( redirectUrl.Contains( key ) )
{
Response.Redirect( String.Format( "Message.aspx?{0}={1}", Constants.QueryStringKeys.ERRORMESSAGENAME, authorizationFailureMessages[ key ] ), true );
}
}
}
Roles.IsUserInRole - If you're just using it for this page, throw this in the code behind. If you have a lot of pages, you could consider putting this in a base class and reading either from the web.config or the database per page. I believe this will give you the most control.
I basically agree to @MattPeterson 's solution. But I suggest two improvements.
In my view, you just tell that "according to the roles that you are, you are not allowed to visit that page", that is enough. You do not need to tell which extra roles are needed, which will expose the details of authorization management of your website.
You can get access control list from web.config (in each folder), and no need to write
<add key="MemberResources" value="MembershipRequired" />
again.
I believe you should have something similar to
<authorization>
<deny users="?" />
</authorization
in your web.config.
精彩评论