给出以下代码:
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;
}
}
将几乎所有方法体提取到授权过滤器中是否有意义?如果没有两次检索备份,我就没有办法做到这一点。
您如何将授权问题与控制器操作分开?
答案 0 :(得分:3)
为了将安全逻辑与控制器逻辑分开,我更喜欢使用Http Headers在浏览器和控制器之间传送安全令牌,并检查自定义AuthorizeAttribute
例如;
在JQuery的beforeSend
函数中,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
答案 1 :(得分:0)
您要求的是技术上可行的。比如说,您实现了一个动作过滤器,并在重写的OnActionExecuted中设置了一些逻辑,将状态代码设置为Forbidden。我没有这样做,只是建议您探索可行性。 OnActionExecuted在action方法之后运行,它可以访问备份。
另一个更好的选择是使用基于声明的标识并实现ClaimsAuthorizationManager的子类。 CheckAccess(AuthorizationContext)接受操作声明和资源声明。与备份相关的属性可以作为资源声明传递。