简体   繁体   English

在Web Api,服务层和数据库中检查用户访问权限的更好方法

[英]Better approach to check users access in Web Api, Service layer, DB

Users are assigned to one or more departments. 用户被分配到一个或多个部门。

Users have one or more roles for instance, Read Own role can only view his/her Tasks. 例如,用户具有一个或多个角色,“ 只读”角色只能查看其任务。 While Team Member role can view and edit others Tasks within department he/she is assigned to. 尽管“ 团队成员”角色可以查看和编辑分配给他/她的部门中的其他任务。 User with role Admin can view and edit all Tasks in the system. 具有管理员角色的用户可以查看和编辑系统中的所有任务。

Due to unauthorized access prevention and performance reasons we want to pass the current logged in user id all the way down to the database to be able only fetch the records he/she has access to. 由于未经授权的访问保护和性能原因,我们希望将当前登录的用户ID一直传递到数据库,以便仅能提取他/她有权访问的记录。

Our system design is: 我们的系统设计是:

Web API -> Business/Service layer -> Repositories -> DB Web API->业务/服务层->存储库-> DB

Currently we are passing User id from web API to service layer in each method where it checks for instance if user has role Team Member (who can view/edit other users Tasks within departments he has access to) and gets all the Departments he has access to and then that is passed further to the Repositories. 当前,我们通过每种方法将用户ID从Web API传递到服务层,在这种方法中,它检查例如用户是否具有团队成员角色(谁可以查看/编辑其他用户他有权访问的任务)并获取他有权访问的所有部门。到,然后进一步传递到存储库。

Is there any better approach to avoid passing user id in each method? 有没有更好的方法来避免在每种方法中传递用户ID? What is the best place in the above design to check for users Access? 以上设计中检查用户访问权限的最佳位置是什么?

We ideally want the method without user id parameter to be able to use the same classes for reporting in another application. 理想情况下,我们希望没有用户ID参数的方法能够使用相同的类在另一个应用程序中进行报告。

Any ideas? 有任何想法吗?

Use dependency injection to inject some ICurrentUser instance to the services that require the user id to perform queries and other tasks. 使用依赖项注入将一些ICurrentUser实例注入到需要用户ID来执行查询和其他任务的服务中。

public interface ICurrentUser
{
    int UserId { get; }
}

public class AspNetCurrentUser : ICurrentUser
{
    public int UserId { get { return HttpContext.Current.User.GetUserId<int>(); } }
}

public class Service : IService
{
    private readonly ICurrentUser _currentUser;

    public Service(ICurrentUser currentUser)
    {
        _currentUser = currentUser;
    }

    public object WorkWithUserId()
    {
        return _currentUser.UserId;
    }
}

Have a Security Layer (comprised of classes that decorate your service layer classes) that checks if the user has rights to raise the request. 拥有一个安全层(由装饰您的服务层类的类组成)检查用户是否有权提出请求。

For instance if your Web API call is to ../viewTask/456 check if the user is Admin, Team member of the department to which the task belongs to or if its his/her own task. 例如,如果您的Web API调用是../viewTask/456请检查用户是否为Admin,任务所属部门的团队成员或他/她自己的任务。

The decorator classes pass down to the wrapped service layer class if the access control check passes or raise an Unauthorized exception if it fails. 如果访问控制检查通过,则装饰器类传递给包装的服务层类;如果失败,则引发未授权的异常。

Something like... 就像是...

public class SecuredTaskController : ApiController
{
    private IContext _context;
    private ITaskService _taskService;
    // other services needed for access check (eg. userService?)

    public SecuredTaskController(ITaskService taskService, IContext context
        // other services needed for access check (eg. userService?)
        )
    {
        _taskService = taskService;
        _context = context;
    }

    public IHttpActionResult Get(Task task)
    {
        if (hasGetAccess(task, _context.UserId))
            return Ok(_taskService.Get(task));
        else
            return Unauthorized();
    }

    private bool hasGetAccess(Task task, long userId)
    {
        // check if userId has acces to get task
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM