我有一个 asp.net web api。
我想稍后在一个 Azure 网站上自行托管我的 Web API。
登录用户可以在浏览器中执行此操作 /api/bankaccounts/3
获取有关银行帐号 3
的所有详细信息。
但登录用户不是银行帐号3
的所有者。
我必须如何设计我的 Controller 及其背后的服务
在数据库中用户只能检索/修改自己的资源吗?
更新
在我创建一个之后:
public class UserActionsAuthorizationFilter : AuthorizationFilterAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
if (actionContext != null)
{
bool canUserExecuteAction = IsResourceOwner(actionContext);
// stop propagation
}
}
private bool IsResourceOwner(HttpActionContext actionContext)
{
var principal = (ClaimsPrincipal)Thread.CurrentPrincipal;
var userIdAuthenticated = Convert.ToInt32(principal.Claims.Single(c => c.Type == ClaimTypes.Sid).Value);
int targetId = Convert.ToInt32(actionContext.Request.GetRouteData().Values["Id"]);
var requstScope = actionContext.ControllerContext.Request.GetDependencyScope();
var service = (ISchoolyearService)requstScope.GetService(typeof(ISchoolyearService));
bool canUserExecuteAction = service.HasUserPermission(userIdAuthenticated, targetId);
return canUserExecuteAction;
}
}
现在的问题是 IsResouceOwner 被硬编码到某个服务 => SchoolyearService 因此绑定(bind)到 Schoolyear SQL 表
我需要让 IsResourceOwner 方法对所有具有字段 UserId/UserEmail 的 sql 表保持通用。
问题是 - 我真的认为没有人这样做 - 我必须在 HasUserPermission 方法中将每个资源所有者检查映射到正确的 Sql 表。
映射应该是什么样子的?
检查 Controller 名称“SchoolyearController”因此要检查的表是“schoolyear”表?太荒谬了。
这个自定义属性“UserActionsAuthorizationFilter”将出现在每个“数据” Controller 上。
无论用户触发什么 Controller url 来获取数据,在我必须检查他是否是资源所有者之前。
我想我无法在过滤器中决定这一点。
我必须让数据检索/修改通过 Controller ,并在数据检索完成之前在存储库中进行 ResourceOwner 检查。
你怎么看这个:
API
public async Task<IHttpActionResult> Delete(int id)
{
var result = await service.Delete(id, User.Identity.UserId);
if (result == 0)
return NotFound();
return Ok();
}
repo
public async Task<int> Delete(int id, int userId)
{
var schoolyerToDelete = await context.Schoolyears.SingleOrDefaultAsync(s => s.Id == id && s.UserId == userId);
// If schoolyearToDelete is null nothing is removed, thus the affected rows are ZERO.
context.Schoolyears.Remove(schoolyerToDelete);
return await context.SaveChangesAsync();
}
- 对于错误的 UserId,Get 方法不会返回任何内容
- 对于 Create 方法:没问题,如果登录,每个人都应该能够创建资源。
- 对于 Update 方法:与 Delete 方法相同,学年由 id 和 UserId 检索。
一般来说,我存储库中的每个方法都应该考虑 CRUD 操作中的 UserId。
你怎么看?
最佳答案
这是一个老问题,但对于遇到类似问题的任何人,这里有一个可能的解决方案。
添加一个抽象层
- 您可以像以前一样使用 UserActionsAuthorizationFilter 来凑合;只需执行以下操作
- 让你所有的服务接口(interface)(比如 ISchoolyearService)继承一个定义了 HasUserPermission 的通用接口(interface)
public interface IService {
HasUserPermission(int32 userIdAuthenticated, int targetId));}
public interface ISchoolyearService : IService {
/* Include all other methods except for HasUserPermission */
}
- 在 UserActionsAuthorizationFilter 中,添加一个字段:“internal IService ServiceProvider”
- 在 UserActionsAuthorizationFilter 中,修改 IsResourceOwner():
来自
var service = (ISchoolyearService)requstScope.GetService(typeof(ISchoolyearService));
到
var service = (IService)requstScope.GetService(this.ServiceProvider);
- Then, change all the attributes on your Controllers to specify which type of IService they use
[UserActionsAuthorizationFilter(ServiceProvider = typeof(ISchoolyearService))] <br> internal SchoolyearController : Controller { }
这种方法的显着缺点是您随后 promise 仅允许用户访问通过 HasUserPermission()
检查的用户,因此您无法进行任何操作应该可以公开访问的更深层次的 URL,例如 /api/testresults/3/public
P.S> 你是对的,根据 Controller 名称找出要检查哪个 SQL 表是荒谬的😊
关于c# - 如何保护 Web API 免受数据检索而不是来自资源所有者的数据检索,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30817347/