WEB API - 在控制器或操作级别授权(无身份验证)

WEB API - Authorize at controller or action level (no authentication)

我有一个没有身份验证的现有 API。这是一个 public Web API,多个客户端通过发出简单的请求来使用它。

现在,需要授权访问某个方法

有什么方法可以做到这一点,为已经使用此 Web API 的客户端保留其余的控制器和各自的方法 "open"?

如何确定请求是否有权访问此 "protected" 方法?

您可以在特定的 API 方法以及控制器级别使用 [Authorize] 属性。如果您将 [Authorize] 属性放在控制器级别,那么您可以将 [AllowAnonymous] 属性用于那些您希望无需身份验证即可访问的 API 方法。

您需要做的是向您想要保护的方法添加一个 [Authorize] 属性,可选择使用接受一个或多个调用用户必须在其中的角色名称的重载。

那么您必须实现的是一种确保将调用者的身份验证数据转换为 Principal 对象的方法。设置 Principal 通常不是您自己做的事情,而是让框架为您做。

如果您确实想提供自己的界面,您可以使用实现 System.Web.Http.Filters.IAuthenticationFilter 界面的身份验证过滤器。

那么你会得到的是:

[MyAuthentication]
[Authorize]
public SomeClass MyProtectedMethod() {
    return new SomeClass();
}

然后实现MyAuthentication属性。下面是一个示例,重要的是您使用传入请求的上下文并最终使用新的 Principal

设置 context.Principal 属性
public class MyAuthentication : ActionFilterAttribute, System.Web.Http.Filters.IAuthenticationFilter {

    public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
    {
        // 1. Look for credentials in the request.
        HttpRequestMessage request = context.Request;
        AuthenticationHeaderValue authorization = request.Headers.Authorization;

        // 2. If there are no credentials, do nothing.
        if (authorization == null)
        {
            return;
        }

        // 3. If there are credentials but the filter does not recognize the 
        //    authentication scheme, do nothing.
        if (authorization.Scheme != "Basic")
        {
            return;
        }

        // 4. If there are credentials that the filter understands, try to validate them.
        // 5. If the credentials are bad, set the error result.
        if (String.IsNullOrEmpty(authorization.Parameter))
        {
            context.ErrorResult = new AuthenticationFailureResult("Missing credentials", request);
            return;
        }

        Tuple<string, string> userNameAndPasword = ExtractUserNameAndPassword(authorization.Parameter);
        if (userNameAndPasword == null)
        {
            context.ErrorResult = new AuthenticationFailureResult("Invalid credentials", request);
        }

        string userName = userNameAndPasword.Item1;
        string password = userNameAndPasword.Item2;

        IPrincipal principal = await AuthenticateAsync(userName, password, cancellationToken);
        if (principal == null)
        {
            context.ErrorResult = new AuthenticationFailureResult("Invalid username or password", request);
        }

        // 6. If the credentials are valid, set principal.
        else
        {
            context.Principal = principal;
        }

    }


    ... other interface methods here
}

我希望这可以帮助您走上正轨。有关详细信息,请查看此 post: http://www.asp.net/web-api/overview/security/authentication-filters

默认情况下,应用程序全局禁用授权。您可以通过添加操作过滤器 [Authorize].

强制您的控制器只允许授权请求
[Authorize]  // This will enforce all methods inside should be authorized
public class AuthorizeController : ApiController
{
      //this method will only be called if user is authorized
      public IHttpActionResult GetList()
      {
         return Ok();
      }
}

您也可以强制只授权某些方法:

public class AuthorizeController : ApiController
{
      [Authorize] //this method will only be called if user is authorized
      public IHttpActionResult GetList()
      {
         return Ok();
      }

      // This method can still be called even if user is not authorized
      public IHttpActionResult GetListUnauthorized()
      {
         return Ok();
      }
}

或者只是在需要授权的控制器中禁用某些方法的授权:

[Authorize]
public class AuthorizeController : ApiController
{
      //this method will only be called if user is authorized
      public IHttpActionResult GetList()
      {
         return Ok();
      }

      [AllowAnonymous]// This method can be called even if user is not authorized due the AllowAnonymous attribute
      public IHttpActionResult GetListUnauthorized()
      {
         return Ok();
      }
}

您还可以使用以下方式设置允许谁访问您的方法:

[Authorize(Users="Joey,Billy")]

或按规则使用:

[Authorize(Roles="Administrator,Manager")]

或者甚至构建一个更复杂的授权属性,就像这个答案(基于声明):Authorization Attribute by Claims

我们在方法上使用 [AllowAnonymous] 解决了这个问题,我们不想对谁进行身份验证但已授权,覆盖了授权。

执行流程将进入方法级别,然后进入控制器级别。因此,如果您提到 "AllowAnonymous" 将在没有授权检查的情况下执行。