2

给定以下代码:

public class BackupsController : ApiController
{
    private readonly IApiContext context;
    private readonly IBackupService backupService;

    public BackupsController(IApiContext context, IBackupService backupService)
    {
        this.context = context;
        this.backupService = backupService;
    }

    public HttpResponseMessage Get(Guid id)
    {
        if (id == Guid.Empty)
        {
            throw new HttpResponseException(HttpStatusCode.BadRequest);
        }

        IBackupView backup = backupService.Get(id);

        if (backup == null)
        {
            return Request.CreateErrorResponse(HttpStatusCode.NotFound, String.Format("BackupId '{0}' not found.", id));
        }

        if (!IsAuthorizedForBackup(backup))
        {
            throw new HttpResponseException(HttpStatusCode.Forbidden);
        }

        return Request.CreateResponse(HttpStatusCode.OK, backup);
    }

    private bool IsAuthorizedForBackup(IBackupView backup)
    {
        if (context.Principal.IsInRole(MembershipRole.Admin))
        {
            return true;
        }

        if (context.Principal.AllowDataSharing && backup.UserId == context.Principal.UserId)
        {
            return true;
        }

        if (backup.UserId == context.Principal.UserId && backup.Device.Uuid == context.DeviceUuid)
        {
            return true;
        }

        return false;
    }
}

将几乎所有方法主体提取到授权过滤器中是否有意义?如果不检索两次备份,我看不到这样做的方法。

您将如何将授权问题与控制器操作分开?

4

2 回答 2

3

为了将安全逻辑与控制器逻辑分开,我更喜欢使用 Http 标头在浏览器和控制器之间携带安全令牌,并在自定义中检查该标头值AuthorizeAttribute

例如;

beforeSendJQuery 的 ajax 函数中设置安全令牌(之前取自服务器,见下文)

beforeSend: function (xhr) {
    xhr.setRequestHeader('requestToken', model.requestToken);
}

在自定义中检查令牌AuthorizeAttribute

public class AuthAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(HttpActionContext actionContext)
    {
        var token = HttpContext.Current.Request.Headers["requestToken"];
        // Do the authorization based on token
    }
}

[Auth]使用自定义属性装饰控制器,其操作需要授权,例如:

[Auth]
public class SomeController : ApiController

我们可以使用 Http Headers 再次将新令牌发送回客户端

HttpContext.Current.Response.Headers["requestToken"] = Guid.NewGuid();

在客户端,您可以将其存储在 JQuery 的 ajax 函数的成功函数中,以便在请求中发回

success: function (res, status, xhr) {
    model.requestToken = xhr.getResponseHeader('requestToken');
}

这可能无法完美处理您的情况,但主要思想是在 Http Headers 中携带(最好是加密的)安全数据并在自定义中处理安全问题AuthorizeAttribute

于 2013-04-09T06:09:24.547 回答
0

您所要求的在技术上是可行的。假设您实现了一个操作过滤器,并在重写的 OnActionExecuted 中有一些逻辑将状态代码设置为 Forbidden。我没有这样做,这只是一个建议,供您探索可行性。OnActionExecuted 在 action 方法之后运行,它可以访问备份。

另一个更好的选择是使用基于声明的身份并实现 ClaimsAuthorizationManager 的子类。CheckAccess(AuthorizationContext) 接受操作声明和资源声明。与备份相关的属性可以作为资源声明传递。

于 2013-04-09T18:15:43.297 回答