2012-06-08 65 views
4

我試圖在MVC3中做一件簡單的事情。使用Forms身份驗證的MVC3中的簡單授權

我有一個應用程序使用表單身份驗證來驗證用戶與第三方SSO。 SSO在成功登錄後發回到我的應用程序中的特定控制器操作。然後我打電話給FormsAuthentication.SetAuthCookie(user,false);

我試圖實現某種程度的授權。簡而言之,用戶可以以多種不同的角色存在,例如, AdminDeveloper。某些控制器操作應僅適用於某些角色。通過調用另一個外部API來獲得用戶所屬角色的詳細信息,該API將返回一個簡單的JSON響應指示。

從理論上講,這應該是爲做這樣的事情簡單經過我設置FormsAuthentication餅乾:

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

但是,我不能打電話SetAuthCookie後直接調用此方法,因爲HttpContext.User沒有什麼在這一點上有意義。

我可以嘗試在每個請求上設置此項,但對我的應用程序的請求將意味着來回API調用。

最有前途的方法到目前爲止,我所看到的是創建一個自定義的授權屬性,並覆蓋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行程。

這是最好的方法是什麼?

+0

很好的問題.... –

回答

1

我的第一個想法是,你應該調查實現一個自定義角色提供者。這可能是過度的,但似乎與基於角色的管道配合。

更多的信息MSDN here

+0

這實際上並不是一個糟糕的做法,儘管起初看起來令人望而生畏。創建一個類非常簡單,從RoleProvider繼承並實現一些方法來調用API來獲取角色信息。中間有一些簡單的緩存,它似乎工作得很好。額外的好處是,我可以將其拉入單獨的dll,並通過nuget分發給所有想要針對此特定API授權的應用程序。 – growse

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

更新

我有錯誤的方法簽名(只是在我自己的應用程序中進行檢查)。

+0

BRB,關閉做一些測試這個:) – growse

+0

@jgauffin - 這看起來很有趣,但我想知道這些信息是如何獲取的堅持在後續請求。 –

+0

看起來這是持久的,在'Master.cshtml'上放置'IsAdmin:@ User.Identity.IsInRole(「Admin」)'在每個頁面上都顯示爲'True'。 – growse

2

另一種方法是將角色存儲在FormsAuthentcationTicket的UserData屬性中。這可以用逗號分隔的字符串完成。

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

然後在AuthenticateRequest方法,你可以拉回來票,搶角色的數據並將其分配給使用通用的本金當前用戶。

+0

這是一個好主意 - 我可以存儲一個緩存timout值,以防我想在用戶會話期間多次刷新角色列表(比如每隔5分鐘)。 – growse

1

很多人對此感到震驚,會話對象ISNT在這裏是一個壞主意。 如果您使用臨時數據,您已經擊中了會話。

將這些數據存儲在cookie中 - 從一年半前開始,表單認證令牌已經在POET漏洞中被利用,所以在這種情況下,有人可以簡單地使用「admin」使用該漏洞的字符串。

你可以在後面進行身份驗證,就像@jgauffin提到的一樣。 如果會話狀態不可用,那麼您可以在Application_PreRequestHandlerExecute中使用它並在那裏檢查它。

如果你想檢查是否會話狀態是可用任一看到我的代碼爲: How can I handle forms authentication timeout exceptions in ASP.NET?

而且每當使用窗體身份驗證和會話,你總是希望確保超時是在彼此同步(再上面的代碼)