使用表单身份验证在MVC3中进行简单授权

时间:2012-06-08 12:42:29

标签: asp.net-mvc-3 forms-authentication authorization

我正在尝试在MVC3中做一件简单的事情。

我有一个应用程序,它使用表单身份验证来验证具有第三方SSO的用户。成功登录后,SSO会回复我的应用程序上的特定控制器操作。然后我拨打FormsAuthentication.SetAuthCookie(user,false);

我正在尝试实施某种程度的授权。简单地说,用户可以存在许多不同的角色,例如AdminDeveloper。某些控制器操作应仅适用于某些角色。通过调用另一个外部API来获取用户所属角色的详细信息,该API返回一个简单的JSON响应指示。

理论上,在设置FormsAuthentication cookie后,这应该像执行此类操作一样简单:

string[] rolelist = GetRoleListForUserFromAPI(User.Identity.Name);
HttpContext.User = new GenericPrincipal(User.Identity, rolelist);

但是,在调用SetAuthCookie后我无法直接调用此内容,因为HttpContext.User此时没有任何意义。

我可以尝试在每个请求上设置此项,但是对我的应用程序的请求将意味着进行往返API调用。

到目前为止,我见过的最有希望的方法是创建自定义Authorization属性并覆盖OnAuthorization来执行以下操作:

public override void OnAuthorization(AuthorizationContext filterContext)
{
    if (<some way of checking if roles have already been set for this user, or role cache has timed out>)
    {
        string[] rolelist = GetRoleListForUserFromAPI(filterContext.HttpContext.User.Identity.Name);
        filterContext.HttpContext.User = new GenericPrincipal(filterContext.HttpContext.User.Identity,rolelist);
    }
}

然后我可以在控制器动作前使用[MyCustomAuthorization(Roles="Admin")]来实现魔法。

但是,我不知道如何检测当前HttpContext.User对象是否已设置其角色,或者是否在一段时间之前设置了它,并且需要另一个API旅行。

最好的办法是什么?

4 个答案:

答案 0 :(得分:2)

您应该覆盖PostAuthenticateRequest

protected void Application_OnPostAuthenticateRequest(object sender, EventArgs e) 
{
    if (HttpContext.Current.User.Identity.IsAuthenticated)
    {
        string[] rolelist = GetRoleListForUserFromAPI(User.Identity.Name);
        HttpContext.User = new GenericPrincipal(User.Identity, rolelist);
    }
}

在表单身份验证完成后进行处理。

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

<强>更新

我的方法签名错误(只在我自己的应用程序中检查过)。

答案 1 :(得分:2)

另一种方法是将角色存储在FormsAuthentcationTicket的UserData属性中。这可以用逗号分隔的字符串来完成。

http://msdn.microsoft.com/en-us/library/system.web.security.formsauthenticationticket.formsauthenticationticket

然后在AuthenticateRequest方法上,您可以拉回故障单,获取角色数据并使用通用主体将其分配给当前用户。

答案 2 :(得分:1)

我首先想到的是您应该调查实现自定义角色提供程序。这可能是矫枉过正,但似乎适合基于角色的管道。

来自MSDN here的更多信息。

答案 3 :(得分:1)

令人骇人听闻的是,会话对象ISNT在这里是一个坏主意。 如果您使用临时数据,则您已经为该会话命中了一个。

将这些数据存储在cookie中,从一年半前开始,表单身份验证令牌已经在POET漏洞中被利用了,所以在这种情况下,有人可以简单地用“admin”字符串形成自己的cookie在其中使用该漏洞。

你可以在@jgauffin提到的post authenticate中执行此操作。 如果会话状态不可用,那么您可以在Application_PreRequestHandlerExecute中使用它并在那里进行检查。

如果您想检查会话状态是否可用,请参阅我的代码: How can I handle forms authentication timeout exceptions in ASP.NET?

每当使用表单身份验证和会话时,您总是希望确保超时彼此同步(再次使用上面的代码)