首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于Asp.net核心WebAPI资源的外部控制器级授权

基于Asp.net核心WebAPI资源的外部控制器级授权
EN

Stack Overflow用户
提问于 2020-04-16 20:42:23
回答 6查看 3.5K关注 0票数 9

我正在创建一个具有不同角色的用户的Web,此外,作为任何其他应用程序,我不希望用户A访问用户B的资源。如下所示:

订单/1(用户A) 订单/2(用户B)

当然,我可以从请求中获取JWT,并查询数据库以检查该用户是否拥有该订单,但这将使我的控制器操作太重。

这个示例使用AuthorizeAttribute,但它似乎太宽泛了,我将不得不为API中的所有路由添加大量的条件,以检查访问的是哪一条路由,然后查询数据库,进行几个连接,这些连接将导致返回uses表,如果请求是否有效,则返回。

更新 对于路线,第一道防线是一种安全策略,它需要某些要求。 我的问题是关于第二条防线,它负责确保用户只访问他们的数据/资源。

在这种情况下有什么标准的方法要采取吗?

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2020-04-23 20:43:00

我采取的方法是自动将查询限制到当前通过身份验证的用户帐户拥有的记录。

我使用一个接口来指示哪些数据记录是帐户特定的。

代码语言:javascript
复制
public interface IAccountOwnedEntity
{
    Guid AccountKey { get; set; }
}

并提供一个接口,以注入用于识别存储库应该针对哪个帐户的逻辑。

代码语言:javascript
复制
public interface IAccountResolver
{
    Guid ResolveAccount();
}

我今天使用的IAccountResolver的实现基于经过身份验证的用户声明。

代码语言:javascript
复制
public class ClaimsPrincipalAccountResolver : IAccountResolver
{
    private readonly HttpContext _httpContext;

    public ClaimsPrincipalAccountResolver(IHttpContextAccessor httpContextAccessor)
    {
        _httpContext = httpContextAccessor.HttpContext;
    }

    public Guid ResolveAccount()
    {
        var AccountKeyClaim = _httpContext
            ?.User
            ?.Claims
            ?.FirstOrDefault(c => String.Equals(c.Type, ClaimNames.AccountKey, StringComparison.InvariantCulture));

        var validAccoutnKey = Guid.TryParse(AccountKeyClaim?.Value, out var accountKey));

        return (validAccoutnKey) ? accountKey : throw new AccountResolutionException();
    }
}

然后,在存储库中,我将所有返回的记录限制为由该帐户拥有。

代码语言:javascript
复制
public class SqlRepository<TRecord, TKey>
    where TRecord : class, IAccountOwnedEntity
{
    private readonly DbContext _dbContext;
    private readonly IAccountResolver _accountResolver;

    public SqlRepository(DbContext dbContext, IAccountResolver accountResolver)
    {
        _dbContext = dbContext;
        _accountResolver = accountResolver;
    }

    public async Task<IEnumerable<TRecord>> GetAsync()
    {
        var accountKey = _accountResolver.ResolveAccount();

        return await _dbContext
                .Set<TRecord>()
                .Where(record => record.AccountKey == accountKey)
                .ToListAsync();
    }


    // Other CRUD operations
}

使用这种方法,我不需要记住对每个查询应用我的帐户限制。这只是自动发生的。

票数 4
EN

Stack Overflow用户

发布于 2020-04-23 20:17:40

使用[Authorize]属性称为声明性授权。但它是在控制器或操作执行之前执行的。当您需要基于资源的授权,并且文档具有author属性时,必须在授权评估之前从存储中加载文档。这叫做强制授权。

Microsoft上有一个帖子如何处理ASP.NET核心中的命令式授权。我认为它是相当全面的,它回答了你关于标准方法的问题。

此外,这里还可以找到代码示例。

票数 4
EN

Stack Overflow用户

发布于 2020-04-28 08:54:09

以确保用户A不能使用Id=2查看订单(属于用户B)。我会做两件事中的一件:

One:有一个GetOrderByIdAndUser(long orderId, string username),当然您可以从jwt获取用户名。如果用户不拥有订单,他就不会看到它,也不会有额外的db-调用。

2:首先从数据库中获取Order GetOrderById(long orderId),然后验证该订单的username-属性与jwt中登录的用户相同。如果用户不拥有订单抛出异常,返回404或任何东西,并且没有额外的db-调用。

代码语言:javascript
复制
void ValidateUserOwnsOrder(Order order, string username)
{
            if (order.username != username)
            {
                throw new Exception("Wrong user.");
            }
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61259702

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档