【问题标题】:Subclassing AuthorizeAttribute with WebApi not working returns 401?使用 WebApi 子类化 AuthorizeAttribute 不起作用返回 401?
【发布时间】:2012-10-21 14:02:31
【问题描述】:

我将 AuthorizeAttribute 子类化,因此我可以实现令牌身份验证,从而将令牌传递到请求标头中。我还在为 IoC 使用 Ninject。覆盖的 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);

    }        

【问题讨论】:

    标签: ninject asp.net-web-api asp.net-authorization


    【解决方案1】:

    我设法通过覆盖 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);
        }
    }
    

    【讨论】:

    【解决方案2】:

    ASP.NET WebAPI 是一个开源项目。所以你可以在这里阅读相应的代码:

    AuthorizationFilterAttribute 在做出决定时需要考虑两个事实:

    1. OnAuthorization 是否抛出异常;或
    2. actionContext的Response字段是否被填满;

    任何一个都实现了,剩下的动作过滤器和动作都是快捷方式。

    根据您的代码,我很好奇函数 HandleUnauthorizedRequest 是否执行上述任一操作。

    重写 IsAuthorized 之所以起作用,是因为它在 AuthorizeAttribute 级别起作用。 OnAuthorization 调用 IsAuthorized 重载并将值设置为 actionContext 的 Request 属性。

    谢谢, 特洛伊

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-01-01
      • 2016-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多