ASP.NET MVC4 настраиваемая авторизация
Я реализовал пользовательский атрибут авторизации в ASP.NET MVC4, переопределив AuthorizeAttribute
сделать пользовательскую авторизацию. Я хочу реализовать это на определенных контроллерах и действиях контроллеров, чтобы они отклоняли неавторизованные запросы, такие как запрос пользователя, не вошедшего в систему, и / или определенные проблемы с правами. Я не хочу реализовывать членство и авторизацию asp.net, приведенный ниже код:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Diagnostics.CodeAnalysis;
using System.Security.Principal;
using System.Web.Mvc.Properties;
using System.Web.Routing;
namespace TestMVC4
{
public sealed class AuthorizeUserAttribute : AuthorizeAttribute
{
private static readonly string[] _emptyArray = new string[0];
string activities;
string[] activitiesList = _emptyArray;
string roles;
string[] rolesList = new string[0];
/// <summary>
/// Gets or sets list of authorized activities
/// </summary>
public string Activities
{
get { return activities ?? String.Empty; }
set
{
activities = value;
activitiesList = SplitString(value);
}
}
public string CRole
{
get { return roles ?? String.Empty; }
set
{
roles = value;
rolesList = SplitString(value);
}
}
/// <summary>
/// Authorization initial call
/// </summary>
/// <param name="filterContext">Filter context</param>
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (OutputCacheAttribute.IsChildActionCacheActive(filterContext))
{
// If a child action cache block is active, we need to fail immediately, even if authorization
// would have succeeded. The reason is that there's no way to hook a callback to rerun
// authorization before the fragment is served from the cache, so we can't guarantee that this
// filter will be re-run on subsequent requests.
//throw new InvalidOperationException(MvcResources.AuthorizeAttribute_CannotUseWithinChildActionCache);
throw new InvalidOperationException("Cannot use within child action cache.");
}
bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true)
|| filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true);
if (skipAuthorization)
{
return;
}
if (AuthorizeCore(filterContext.HttpContext))
{
// ** IMPORTANT **
// Since we're performing authorization at the action level, the authorization code runs
// after the output caching module. In the worst case this could allow an authorized user
// to cause the page to be cached, then an unauthorized user would later be served the
// cached page. We work around this by telling proxies not to cache the sensitive page,
// then we hook our custom authorization code into the caching mechanism so that we have
// the final say on whether a page should be served from the cache.
HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
cachePolicy.SetProxyMaxAge(new TimeSpan(0));
cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);
}
else
{
HandleUnauthorizedRequest(filterContext);
}
}
/// <summary>
/// Main method for overriding custom authorization for application
/// </summary>
/// <param name="httpContext">Current execution context</param>
/// <returns>True/False whether user is authorized for given activity or not respectively</returns>
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
}
//Verify sessionuser roles
if (rolesList != null)
{
String sessionRole = Convert.ToString(httpContext.Session["MyRole"]);
foreach (String role in rolesList)
{
if (role == sessionRole)
return true;
}
}
//IPrincipal user = httpContext.User;
//if (!user.Identity.IsAuthenticated)
//{
// return false;
//}
//if (_usersSplit.Length > 0 && !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase))
//{
// return false;
//}
//if (_rolesSplit.Length > 0 && !_rolesSplit.Any(user.IsInRole))
//{
// return false;
//}
return false;
}
/// <summary>
/// Overriden method for handling unauthorized request routing
/// </summary>
/// <param name="filterContext">Authorization context for which the request has been made</param>
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
// Returns HTTP 401 - see comment in HttpUnauthorizedResult.cs.
filterContext.Result = new HttpUnauthorizedResult();
//filterContext.RequestContext.RouteData;
//filterContext.Result = new RedirectToRouteResult(
// new RouteValueDictionary(
// new
// {
// controller = "Error",
// action = "Unauthorised"
// })
// );
}
private void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus)
{
validationStatus = OnCacheAuthorization(new HttpContextWrapper(context));
}
protected HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext)
{
if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
}
bool isAuthorized = AuthorizeCore(httpContext);
return (isAuthorized) ? HttpValidationStatus.Valid : HttpValidationStatus.IgnoreThisRequest;
}
/// <summary>
/// Splits the string on commas and removes any leading/trailing whitespace from each result item.
/// </summary>
/// <param name="original">The input string.</param>
/// <returns>An array of strings parsed from the input <paramref name="original"/> string.</returns>
string[] SplitString(string original)
{
if (String.IsNullOrEmpty(original))
{
return _emptyArray;
}
var split = from piece in original.Split(',')
let trimmed = piece.Trim()
where !String.IsNullOrEmpty(trimmed)
select trimmed;
return split.ToArray();
}
}
}
Идет нормально, пока OnAuthoriztion
метод вызывается. Проблема в том, что мои пользовательские свойства activities
а также roles
и все остальные переменные становятся пустыми или пустыми. Я не понимаю, почему это происходит. Все эти переменные инициализируются, но все они становятся недействительными, когда он достигает OnAuthorization
функция.
2 ответа
Я нашел решение для моей проблемы самостоятельно, я применил AttributeUsage, чтобы ограничить поведение методами класса. Наряду с этим я использовал его свойство AllowMultiple в true, что вызвало проблему и сбрасывало значения моих переменных, поскольку он использует новый экземпляр при каждом выполнении, переопределяя предыдущий. Установите для этой переменной значение false, и это сработало.
Использование
Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(userName),
new string[] {"Roles goes here"});
Тогда пользователь войдет в систему и вы сможете получить доступ к usser
User.Identity.Name
В моем случае у меня есть атрибут
public class BasicHttpAuthorizeAttribute : AuthorizeAttribute
{
protected override bool IsAuthorized(HttpActionContext actionContext)
{
if (Thread.CurrentPrincipal.Identity.Name.Length == 0)
{
if (ValidateUser(userName, password))
Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(userName, "Basic"),
new string[] {});
}
return base.IsAuthorized(actionContext);
}
}
Так что все мои контроллеры, помеченные этим атрибутом, будут использовать пользовательский логин +, если я установлю AllowAnonimous, он также пропустит Auth