简体   繁体   中英

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.

Our system design is:

Web API -> Business/Service layer -> Repositories -> 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.

Is there any better approach to avoid passing user id in each method? 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.

Any ideas?

Use dependency injection to inject some ICurrentUser instance to the services that require the user id to perform queries and other tasks.

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.

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
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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