Подклассификация AuthorizeAttribute с неработающим WebApi возвращает 401?
Я подклассифицирую AuthorizeAttribute, чтобы я мог реализовать аутентификацию токена, посредством чего токен передается в заголовке запроса. Я также использую Ninject для IoC. Переопределенный метод OnAuthorization вызывается и проверяет токен, но я все еще получаю 401.
Любые идеи о том, почему это происходит?
TokenAuthorisationAttribute.cs
public class TokenAuthorisationAttribute : AuthorizeAttribute
{
private readonly IRepository _repository;
public TokenAuthorisationAttribute(IRepository repository)
{
_repository = repository;
}
public override void OnAuthorization(
HttpActionContext actionContext)
{
if (!ValidateToken(actionContext.ControllerContext.Request))
HandleUnauthorizedRequest(actionContext);
base.OnAuthorization(actionContext);
}
private bool ValidateToken(HttpRequestMessage request)
{
const string authenticationToken = "Authentication-Token";
var token = request.Headers.GetValues(authenticationToken).FirstOrDefault();
if (token == null)
return false;
var device = _repository.FindSingleOrDefault<Device>(x => x.Id.Equals(token));
if (device == null || !token.Equals(device.Id))
return false;
return true;
}
}
NinjectWebCommon.cs
public static class NinjectWebCommon
{
private static readonly Bootstrapper Bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
Bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
Bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
var connectionString = ConfigurationManager.ConnectionStrings["MONGOHQ_URL"].ConnectionString;
var databaseName = ConfigurationManager.AppSettings["Database"];
kernel.Bind<IRepository>().To<MongoRepository>()
.WithConstructorArgument("connectionString", connectionString)
.WithConstructorArgument("databaseName", databaseName);
kernel.BindHttpFilter<TokenAuthorisationAttribute>(FilterScope.Global);
}
2 ответа
Мне удалось решить эту проблему, переопределив метод IsAuthorized вместо OnAuthorization. Не уверен на 100%, правильный ли это подход? Есть мнения?
public class TokenAuthorisationAttribute : AuthorizeAttribute
{
private readonly IRepository _repository;
public TokenAuthorisationAttribute(IRepository repository)
{
_repository = repository;
}
protected override bool IsAuthorized(HttpActionContext actionContext)
{
if (actionContext.Request.Headers.Authorization == null)
return false;
var authToken = actionContext.Request.Headers.Authorization.Parameter;
var decodedToken = Encoding.UTF8.GetString(Convert.FromBase64String(authToken));
var deviceToken = new DeviceToken(decodedToken);
var device = _repository.FindSingleOrDefault<Device>(x => x.Id.Equals(deviceToken.GetDeviceId()));
if (device != null)
{
HttpContext.Current.User = new GenericPrincipal(new ApiIdentity(device), new string[] {});
return true;
}
return base.IsAuthorized(actionContext);
}
}
ASP.NET WebAPI является проектом с открытым исходным кодом. Таким образом, вы можете прочитать соответствующие коды здесь:
- AuthorizationFilterAttribute http://aspnetwebstack.codeplex.com/SourceControl/changeset/view/03357424caf5
- AuthorizeAttribute http://aspnetwebstack.codeplex.com/SourceControl/changeset/view/03357424caf5
Существует два факта, которые AuthorizationFilterAttribute учитывает при принятии решения:
- OnAuthorization выдает исключение; или же
- Заполнено ли поле Response actionContext;
Любой из них выполняется, остальные фильтры действий и действия являются ярлыками.
Исходя из вашего кода, мне любопытно, выполняет ли функция HandleUnauthorizedRequest одну из указанных выше операций.
Причина, по которой переопределение IsAuthorized работает, заключается в том, что он работает на уровне AuthorizeAttribute. Вызов OnAuthorization для перегрузки IsAuthorized и установка значения для свойства запроса actionContext.
Спасибо Трой