Я бы сохранил эту информацию в части пользовательских данных куки-файла аутентификации. Поэтому, когда пользователь входит в систему:
public ActionResult Login(string username, string password)
{
// TODO: validate username/password couple and
// if they are valid get the roles for the user
var roles = "RoleA|RoleC";
var ticket = new FormsAuthenticationTicket(
1,
username,
DateTime.Now,
DateTime.Now.AddMilliseconds(FormsAuthentication.Timeout.TotalMilliseconds),
false,
roles
);
var encryptedTicket = FormsAuthentication.Encrypt(ticket);
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket)
{
// IIRC this property is only available in .NET 4.0,
// so you might need a constant here to match the domain property
// in the <forms> tag of the web.config
Domain = FormsAuthentication.CookieDomain,
HttpOnly = true,
Secure = FormsAuthentication.RequireSSL,
};
Response.AppendCookie(authCookie);
return RedirectToAction("SomeSecureAction");
}
Затем я написал бы собственный атрибут authroize, который позаботится о чтении и разборе билета аутентификации и сохранит универсального пользователя в свойстве HttpContext.User с соответствующими ролями:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext.User.Identity.IsAuthenticated)
{
var authCookie = httpContext.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
var ticket = FormsAuthentication.Decrypt(authCookie.Value);
var roles = ticket.UserData.Split('|');
var identity = new GenericIdentity(ticket.Name);
httpContext.User = new GenericPrincipal(identity, roles);
}
}
return base.AuthorizeCore(httpContext);
}
}
Далее вы можете украсить свои контроллеры / действия этим атрибутом для обработки авторизации:
// Only users that have RoleA or RoleB can access this action
// Note that this works only with OR => that's how the base
// authorize attribute is implemented. If you need to handle AND
// you will need to completely short-circuit the base method call
// in your custom authroize attribute and simply handle this
// case manually
[MyAuthorize(Roles = "RoleA,RoleB")]
public ActionResult Foo()
{
...
}
Чтобы проверить, принадлежит ли пользователь данной роли, просто:
bool isInRole = User.IsInRole("RoleC");
Вооружившись этой информацией, вы можете начать думать о том, как организовать ваши модели представлений. В этих моделях представления я бы включил логические свойства, такие как CanEdit
, CanViewReport
, ..., которые будут заполняться контроллером.
Теперь, если вам нужно это отображение в каждом действии и просмотрах, вещи могут стать повторяющимися и скучными. Здесь вступают в действие глобальные фильтры настраиваемых действий (на самом деле они не существуют в ASP.NET MVC 2, только в ASP.NET MVC 3, поэтому вам может понадобиться базовый контроллер, украшенный этим фильтром действий, который имитирует более или менее то же самое функциональность). Вы просто определяете такой глобальный фильтр действий, который выполняется после каждого действия и внедряет некоторую общую модель представления в ViewData (святой ...., я не могу поверить, что я произношу эти слова) и таким образом делаете его доступным для всех представлений в поперечном направлении Остальные действия.
И, наконец, в представлении вы должны проверить эти свойства логического значения, чтобы включить или не включить различные области сайта. Что касается кода javascript, если он незаметно использует AJAXифицирующие области сайта, то если эти области отсутствуют в DOM, этот код не будет работать. А если вам требуется более детальный контроль, вы всегда можете использовать атрибуты HTML5 data-*
в ваших элементах DOM, чтобы давать подсказки вашим внешним функциям javascript при авторизации пользователя.