使用IPrincipal in和MVC3 AuthorizationAttribute,避免使用RoleProvider

本文关键字:RoleProvider AuthorizationAttribute IPrincipal in MVC3 使用 | 更新日期: 2023-09-27 18:18:12

我有一个WCF服务,它返回一个同时实现了IPrinciple和IIdentity的对象。

我假设我可以把它连接到MVC3授权系统,而不必创建一个角色提供者

。所以我可以在我的AccountController logon方法中这样做:

// AthenticatedUser implments both IPrinciple and IIdentity
AthenticatedUser user = wcfService.Logon(password, userName);
FormsAuthentication.SetAuthCookie(userName, false);
// Set IPrinciple so I can use IsInRole method elsewhere (or AuthorizationAttribute can reuse it)
this.HttpContext.User = authenticationClient.AuthenticatedUser;
当我使用 时

[Authorize (Roles = "foo", "bar")]

我的AuthenticatedUser的IsInRole方法被调用。

然而,在我的测试/调试中,我发现this.HttpContext.User似乎不能跨请求维护。

编辑抱歉:我应该明确表示,我不想在每个请求上调用我的WCF服务,我想以某种方式缓存/存储用户和角色,并能够使用AuthorizeAttribute与来自我的服务的IPrinciple。

有人能帮忙吗?提前感谢!

使用IPrincipal in和MVC3 AuthorizationAttribute,避免使用RoleProvider

如果您使用IIS 7在本地机器上运行此程序,请将此添加到web。在system.webServer下配置:

<modules runAllManagedModulesForAllRequests="true">
    <remove name="FormsAuthentication" />
      <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />
      <remove name="UrlAuthorization" />
      <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />
      <remove name="DefaultAuthentication" />
      <add name="DefaultAuthentication" type="System.Web.Security.DefaultAuthenticationModule" />
      <remove name="RoleManager" />
      <add name="RoleManager" type="System.Web.Security.RoleManagerModule" />
</modules>

你说"this.HttpContext. "用户似乎没有维护跨请求"——这是正确的行为。每个请求都有一个唯一的HttpContext

你可能想尝试的是:

FormsAuthentication.SetAuthCookie(userName, true);

,在浏览器会话之间创建持久cookie。

http://msdn.microsoft.com/en-us/library/bk50ykcd.aspx

正如您所发现的,HttpContext不是跨请求持久的,因此IPrincipalIIdentity也不是- HttpContext是在框架的每个请求开始时构造的,IPrincipalIIdentity是从身份验证cookie反序列化的身份验证票证构造的。

你所描述的在某些方面听起来类似于WCF认证服务。在此场景中,服务将对用户进行身份验证,并在对调用应用程序的响应中发回身份验证cookie,然后该应用程序将使用该cookie在每个后续请求上构造IPrincipalIIdentity

Application.PostAuthenticateRequest事件被引发时,您可以覆盖IPrincipalIIdentity

protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
    if (Context.User != null)
    {
        var identity = Context.User.Identity;
        // define our own IIdentity and IPrincipal for an authenticated user
        if (identity.IsAuthenticated)
        {
            HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
            var ticket = FormsAuthentication.Decrypt(authCookie.Value);
            // get the roles from somewhere
            var roles = GetRoles(); 
            identity = new CustomIdentity(ticket.Name);
            IPrincipal principal = new CustomPrincipal(identity, roles);
            Context.User = Thread.CurrentPrincipal = principal;
        }
    }
}

您可以看到需要从某处检索角色。有了RoleProvider,这些角色就可以缓存在另一个cookie中。如果你知道你在做什么在安全方面,你可以看看如何复制角色在cookie中序列化和加密。

另一种选择可能是将角色存储在会话中,并且可能适合少量角色。请记住,会话是不可用的,直到PostAcquireRequestState事件被引发,一些7事件在应用程序请求生命周期PostAuthenticateRequest晚。

可以在您的全局视图中对AuthenticateRequest事件作出反应,并像这样更改IIdentity:

public class MvcApplication : System.Web.HttpApplication
{
    public override void Init()
    {
        base.Init();
        this.AuthenticateRequest += new EventHandler(MvcApplication_AuthenticateRequest);
    }
    void MvcApplication_AuthenticateRequest(object sender, EventArgs e)
    {
        if (HttpContext.Current.Request.IsAuthenticated)
        {
            var name = HttpContext.Current.User.Identity.Name;
            var key = "User-" + name;
            var principal = HttpContext.Current.Cache["User-" + name];
            if (principal == null)
            {
                principal = GetYourUserAsIPrincipal();
                // Add to cache for 1 hour with sliding expiration
                HttpContext.Current.Cache.Insert(key, principal, null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(1, 0, 0));
            }
            HttpContext.Current.User = principal ;
        }
    }        
}

EDIT:对于缓存,您可以使用默认的ASP。网络缓存。我编辑了上面的示例。注意,ASP。. NET缓存是线程安全的(http://msdn.microsoft.com/en-us/library/system.web.caching.cache.aspx)

如果将所有的缓存访问逻辑包装到一个类中,那将是最好的。

与任何缓存机制一样:如果您更改了用户角色,则只有在缓存过期时才会反映。