I come to the conclusion I need to ditch the ASP.NET Membership
(for list of reasons).
Now really the only thing I see that I need is creating a cookie(done by Form Authentication
), custom methods for authentication (done) and finally validation based on if they are logged in or by role.
I am stuck on the last one.
I am trying to override the Authorize
(attribute) but I have no clue how to do this. I looked at many examples and each one seems to be done differently then the next. I don't know why they do this or which one I should be using.
Some tutorials seem to do the authentication in the AuthorizeCore
, Some do it in the OnAuthentication
.
Some use some AuthorizationContext
thing and then call this base class.
base.OnAuthorization(filterContext);
Some seem to do caching in it.
What I want is all the functionality the built in ones have but just hooked up to my custom tables. Like I going to have my own Role table. I need to tell it where that is and pull the stuff in.
Also I have no clue how to do this or how decorate the tag like this
[Authorize(Roles="test")]
References:- http://darioquintana.com.ar/blogging/tag/aspnet-mvc/ asp.net mvc Adding to the AUTHORIZE attribute http://davidhayden.com/blog/dave/archive/2009/04/09/CustomAuthorizationASPNETMVCFrameworkAuthorizeAttribute.aspx
Edit
This is what I have now.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public sealed class AuthorizeAttributeCustom : AuthorizeAttribute
{
public string Roles { get; set; }
private void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus)
{
validationStatus = OnCacheAuthorization(new HttpContextWrapper(context));
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
// auth failed, redirect to login page
filterContext.Result = new HttpUnauthorizedResult();
return;
}
DataClasses1DataContext test = new DataClasses1DataContext();
var name = filterContext.HttpContext.User.Identity.Name;
var user = test.User2s.Where(u => u.userName == name).FirstOrDefault();
var role = test.Roles.Where(u => u.UserId == user.userId).Select(u => u.Role1).FirstOrDefault();
string[] split = Roles.Split(',');
if (split.Contains(role) == true)
{
// is authenticated and is in the required role
SetCachePolicy(filterContext);
return;
}
filterContext.Result = new HttpUnauthorizedResult();
}
private void SetCachePolicy(AuthorizationContext filterContext)
{
// ** IMPORTANT **
// Since we're performing authorization at the action level, the authorization code runs
// after the output caching module. In the worst case this could allow an authorized user
// to cause the page to be cached, then an unauthorized user would later be served the
// cached page. We work around this by telling proxies not to cache the sensitive page,
// then we hook our custom authorization code into the caching mechanism so that we have
// the final say on whether a page should be served from the cache.
HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
cachePolicy.SetProxyMaxAge(new TimeSpan(0));
cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);
}
}
Out Standing Questions
Whats the cache refering to? Like is it caching the role? Or the Page? I can't tell with the debugger it seems to run the code every single time.
Is caching it safe?
In general is this safe(ie no holes in it to be explioted- kinda worried I will screw something up and have some major hole in my site).
Here's a custom attribute that would work just as you want it; using an Enum for role types and using cookie creation yourself, which allows for storing of roles.
usage
[AuthorizeAttributeCustom(RoleRequired = GoodRoles.YourRoleTypeHere)]
attribute code:
//http://stackoverflow.com/questions/977071/redirecting-unauthorized-controller-in-asp-net-mvc/977112#977112
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public sealed class AuthorizeAttributeCustom : AuthorizeAttribute
{
/// <summary>
/// The name of the view to render on authorization failure. Default is "Error".
/// </summary>
public string ViewName { get; set; }
public ViewDataDictionary ViewDataDictionary { get; set; }
public DeniedAccessView DeniedAccessView { get; set; }
private GoodRoles roleRequired = GoodRoles.None;
public GoodRoles RoleRequired { get{ return roleRequired;} set{ roleRequired = value;} } // this may evolve into sets and intersections with an array but KISS
public AuthorizeAttributeCustom()
{
ViewName = "DeniedAccess";
DeniedAccessView = new DeniedAccessView
{
FriendlyName = "n/a",
Message = "You do not have sufficient privileges for this operation."
};
ViewDataDictionary = new ViewDataDictionary(DeniedAccessView);
}
private void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus)
{
validationStatus = OnCacheAuthorization(new HttpContextWrapper(context));
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
// auth failed, redirect to login page
filterContext.Result = new HttpUnauthorizedResult();
return;
}
if (RoleRequired == GoodRoles.None || filterContext.HttpContext.User.IsInRole(RoleRequired.ToString()))
{
// is authenticated and is in the required role
SetCachePolicy(filterContext);
return;
}
filterContext.Result = new ViewResult { ViewName = ViewName, ViewData = ViewDataDictionary };
}
private void SetCachePolicy(AuthorizationContext filterContext)
{
// ** IMPORTANT **
// Since we're performing authorization at the action level, the authorization code runs
// after the output caching module. In the worst case this could allow an authorized user
// to cause the page to be cached, then an unauthorized user would later be served the
// cached page. We work around this by telling proxies not to cache the sensitive page,
// then we hook our custom authorization code into the caching mechanism so that we have
// the final say on whether a page should be served from the cache.
HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
cachePolicy.SetProxyMaxAge(new TimeSpan(0));
cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);
}
}
you'll need to have explicitly added your roles to auth cookie and read them back in a base controller say. my implementation has other details which you might not want so maybe best to read here: http://ondotnet.com/pub/a/dotnet/2004/02/02/effectiveformsauth.html
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.