问题
I am building a web application using ASP.NET MVC that has two very distinct types of users. I'll contrive an example and say that one type is content producers (publishers) and another is content consumers (subscribers).
I am not planning on using the built-in ASP.NET authorization stuff, because the separation of my user types is a dichotomy, you're either a publisher or a subscriber, not both. So, the build-in authorization is more complex than I need. Plus I am planning on using MySQL.
I was thinking about storing them in the same table with an enum field (technically an int field). Then creating a CustomAuthorizationAttribute, where I'd pass in the userType needed for that page.
For example, the PublishContent page would require userType == UserType.Publisher, so only Publishers could access it. So, creating this attribute gives me access to the HttpContextBase, which contains the standard User field (of type IPrincipal). How do I get my UserType field onto this IPrincipal? So, then my attribute would look like:
public class PublisherAuthorizationAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (!httpContext.User.Identity.IsAuthenticated)
return false;
if (!httpContext.User.Identity.UserType == UserTypes.Publisher)
return false;
return true;
}
}
Or does anyone think my entire approach is flawed?
回答1:
I would still use the built in ASP.NET forms authentication but just customize it to your needs.
So you'll need to get your User class to implement the IPrincipal interface and then write your own custom cookie handling. Then you can simply just use the built in [Authorize] attribute.
Currently I have something similar to the following...
In my global.asax
protected void Application_AuthenticateRequest()
{
HttpCookie cookie = Request.Cookies.Get(FormsAuthentication.FormsCookieName);
if (cookie == null)
return;
bool isPersistent;
int webuserid = GetUserId(cookie, out isPersistent);
//Lets see if the user exists
var webUserRepository = Kernel.Get<IWebUserRepository>();
try
{
WebUser current = webUserRepository.GetById(webuserid);
//Refresh the cookie
var formsAuth = Kernel.Get<IFormsAuthService>();
Response.Cookies.Add(formsAuth.GetAuthCookie(current, isPersistent));
Context.User = current;
}
catch (Exception ex)
{
//TODO: Logging
RemoveAuthCookieAndRedirectToDefaultPage();
}
}
private int GetUserId(HttpCookie cookie, out bool isPersistent)
{
try
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
isPersistent = ticket.IsPersistent;
return int.Parse(ticket.UserData);
}
catch (Exception ex)
{
//TODO: Logging
RemoveAuthCookieAndRedirectToDefaultPage();
isPersistent = false;
return -1;
}
}
AccountController.cs
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult LogOn(LogOnForm logOnForm)
{
try
{
if (ModelState.IsValid)
{
WebUser user = AccountService.GetWebUserFromLogOnForm(logOnForm);
Response.Cookies.Add(FormsAuth.GetAuthCookie(user, logOnForm.RememberMe));
return Redirect(logOnForm.ReturnUrl);
}
}
catch (ServiceLayerException ex)
{
ex.BindToModelState(ModelState);
}
catch
{
ModelState.AddModelError("*", "There was server error trying to log on, try again. If your problem persists, please contact us.");
}
return View("LogOn", logOnForm);
}
And finally my FormsAuthService:
public HttpCookie GetAuthCookie(WebUser webUser, bool createPersistentCookie)
{
var ticket = new FormsAuthenticationTicket(1,
webUser.Email,
DateTime.Now,
DateTime.Now.AddMonths(1),
createPersistentCookie,
webUser.Id.ToString());
string cookieValue = FormsAuthentication.Encrypt(ticket);
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, cookieValue)
{
Path = "/"
};
if (createPersistentCookie)
authCookie.Expires = ticket.Expiration;
return authCookie;
}
HTHs
Charles
来源:https://stackoverflow.com/questions/1419196/asp-net-mvc-custom-authorization