2009-09-14 136 views
1

我正在构建一个使用ASP.NET MVC的Web应用程序,它有两种非常不同类型的用户。我将举一个例子,说一种类型是内容制作者(发布者),另一种是内容消费者(订阅者)。ASP.NET MVC定制授权

我不打算使用内置的ASP.NET授权的东西,因为我的用户类型的分离是一个二分法,你要么出版商或用户,不能同时使用。所以,内置授权比我需要的更复杂。另外我正在计划使用MySQL。

我想在同一个表中存储他们的枚举场(技术上一个int字段)。然后创建一个CustomAuthorizationAttribute,在那里我传入该页面所需的userType。

例如,PublishContent页面会要求用户类型== UserType.Publisher,所以只有出版商可以访问它。因此,创建此属性使我可以访问HttpContextBase,其中包含标准User字段(IPrincipal类型)。如何将我的UserType字段放到此IPrincipal上?所以,那么我的属性将如下所示:

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; 
    } 
} 

或者没有人认为我的整个方法有缺陷吗?

回答

3

我仍然会使用内置的ASP.NET窗体身份验证,但只是把它定制您的需求。

所以你需要让你的用户类实现IPrincipal接口,然后写自己的自定义cookie处理。然后你可以简单地使用内置的[Authorize]属性。

目前我有类似下面的东西...

在我的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); 
} 

最后我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
查尔斯

+0

这将使在MVC一个无法验证的混乱。绝对不是正确的做法。 – 2010-01-20 05:00:35

+1

无法检测的混乱?几乎不。这是非常短暂的说。 'AccountService'和'FormsAuth'服务都是注入到'AccountController'中的接口 - 使得它们完全可以测试。正如你应该知道的,其他所有的东西都依赖于FormsAuthentication(你还怎么做formauth?),正如默认的ASP.NET MVC项目所指出的那样,它是非常难以测试的。当然,你可以将FormsAuthentication调用提取出来,但是真正要实现的方式是考虑调用它的位置是什么? – Charlino 2010-01-20 08:22:22