开发者

MVC Protecting User Based Data Security

开发者 https://www.devze.com 2022-12-13 01:26 出处:网络
I am starting to dabble with ASP.Net MVC. One question I have is on best practices for protecting user data. For example in the scenario of Sales people, they should only be able to view their own dat

I am starting to dabble with ASP.Net MVC. One question I have is on best practices for protecting user data. For example in the scenario of Sales people, they should only be able to view their own data.

e.g.

SalesData/Edit/14

It is very easy to change the "14" to view other data which they may/开发者_StackOverflow社区or may not have access to.

At this point, I am thinking in my controllers to check for who is logged in, and checking if they have access to the "id" that is getting requested. The problem I see with this, is that this will be application wide, and I am looking for best practices on how to approach this. Should I be looking at CustomControllers? Filters? or what? Any articles/references for how to tackle this would be appreciated.


Set up your methods for retrieving data from your database repository in such a way that you can pass the UserID of the currently logged in person as a parameter. You can then use a permissions table to filter the data to only that data for which the user has access.

The permissions table would have two fields: UserID and ContentID. Once this is set up, it's fairly straightforward to set up CRUD screens so that someone with administrative privileges can set content permissions.


The problem I see with this, is that this will be application wide,

Then you need common service that handles it. Suprisingly, I would call it IAuthorisationService.

and I am looking for best practices on how to approach this. Should I be looking at CustomControllers? Filters? or what?

Whichever way you choose you should use common IAuthorisationService above.
From my experience I can tell that it is easier to inject the service into controller and use it on every action:

/* Interfaces */
public interface IAuthorisationService {
    bool CanEdit(YourItem item);
}

public interface ICurrentUserProvider {
    YourUserEntity GetCurrentUser();
}

/* Implementations */
public class HttpUserProvider : ICurrentUserProvider {
    public YourUserEntity GetCurrentUser() {
        return HttpContext.Current.User.Principal as YourUserEntity;
    }
}

public calss RolesAuthorisationService : IAuthorisationService {
    ICurrentUserProvider userProvider
    public RolesAuthorisationService(ICurrentUserProvider userProvider) {
        this.userProvider = userProvider;
    }

    public bool CanEdit(YourItem item) {
        var u = userProvider.GetCurrentUser();
        if (u == null)
            return false;
        return item.Owner == u && u.IsInRole("EditYourItem");
    }
}

/* Controller */

public class MyController: Controller {
    IAuthorisationService authorisation;

    public MyController(IAuthorisationService authorisation) {
        this.authorisation = authorisation;
    }

    public ActionResult Edit(int id) {
        var item = GetTheItembyIdSomehow();
        if (!authorisation.CanEdit(item))
            return new HttpUnauthorizedResult();

        // Can do this
    }
}

Then you can use ControllerFactory to inject the required dependencies automatically into the controllers:

class DependencyInjectionContainer : WindsorContainer {
    public DependencyInjectionContainer() {
        RegisterDependencies();
    }

    private void RegisterDependencies() {

        // Services
        Register(
            AllTypes.Of<IDiscoverableService>()
                .FromAssembly(typeof(IDiscoverableService).Assembly)
                .Configure(c => c.LifeStyle.Transient)
                .WithService.FromInterface()
            );

        // Controllers
        Register(
            AllTypes.Of<IController>()
                .FromAssembly(typeof(DependencyInjectionContainer).Assembly)
                .Configure(c => c.LifeStyle.Transient)
            );
    }
}

class WindsorControllerFactory : DefaultControllerFactory, IDisposable {
    private readonly IWindsorContainer container;

    public WindsorControllerFactory() {
        container = new DependencyInjectionContainer();
    }

    protected override IController GetControllerInstance(Type controllerType) {
        if (controllerType == null)
            return base.GetControllerInstance(controllerType);
        return (IController) container.Resolve(controllerType);
    }

    public void Dispose() {
        container.Dispose();
    }
}


I use IPrincipal and Authorize(Roles='...') attribute to limit access to actions. IPrincipal is then injected into service layer and user IIdentity is used to filter data.

Example: Users create tasks. Every user can see his tasks. GetTask(int taskId) method first filters by CreatedBy field using identifier from IIdentity and then takes task with specified id. If user doesn't have access to data, method will not return any rows.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号