views:

219

answers:

1

Hello All,

Some Background to begin:

I've implemented a custom MembershipProvider that validates a user from my service layer called "WebMemberShipProvider"

Currently I have a service called "MembershipService", this service implements the interface IMembershipService on the service layer. this MemberShipService queries the dal, and validates a user based on username/password

I've also created a custom AuthorizeAttribute named "AuthorizeOwnerAttribute" and this is where I'm having design issues.

For each controller I have a dependency on a Service. eg. UsersController takes a IUserService in it's constructor.

How can I call AuthorizeAttribute on an ActionResult where the current logged in user and the user being edited have the same "StudioId". Note: I want to use AuthorizeAttribute with multiple controllers, not just "UserController"

So my questions to you are:

  1. What should I do to store the current authenticated user's "StudioId", as this will be used across multiple controllers.
  2. How should I pass authentication down to the service layer, because I want to validate that the requests are valid in the service and data access layers, not just on the client. (If this is advisable, I'm just assuming that validation on the client only is enough if I want to re-use the BLL and DAL later on in a stand-alone application)

Technologies used: - LINQ to SQL via the Repository pattern - ASP.NET MVC Preview 2

Any recommendations or code examples would be very welcomed.

+1  A: 

I basically did my security mostly at the controller level for something like this. I made a decision not to pass things down too far down the chain in order to find out whether or not a person had access to it or if I did I would just make sure IPrincipal.IsInRole() would be enough to satisfy it.

Now I did something else that feels somewhat hackier. I needed to make sure that people that were registered and had this piece assigned to them were the only ones able to access it from this section.

So I created an attribute filter that works much like this:

public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var thingToView = filterContext.ActionParameters[_thingToView] as thingToView ;
            var registration = filterContext.ActionParameters[_registration] as Registration;


            if (!registration.CanSeeThing(thingToView))
            {
                throw new RegistrationCannotViewThing(registration, thingToView);
            }

            base.OnActionExecuting(filterContext);
        }

Now the thing that felt somewhat hacky in this implementation is that I did this on my controller method:

[AuthFilter(ThingToView ="thingToView", Registration="registration")
public ActionResult Method(Thing thingToView, Registration registration)
{
....
}

The actual parameter assignments occurred in the model binder. The security happens through the filter which checks the parameters passed to the method. I then reused this filter in a lot of places.

I did something similar with a model binder to a Scott Hanselman post here: http://www.hanselman.com/blog/IPrincipalUserModelBinderInASPNETMVCForEasierTesting.aspx in order to pass what user is calling a method.

I suppose you can use the example blog post above in order to get your user object to your controller method in order to pass it to your service layer.

Min
There has to be a cleaner SOC way of doing this?This is kind of a last resort for me. Thanks for your input though.
Michael G
Alright upon rereading your post you could just store the studio id in a custom application principal. There are plenty of tutorials you can find in order to set the IPrincipal in an asp.net application.And if you want to pass that authentication down, you could just pass the IPrincipal in your service layer manually or use some AOP techniques. I did try to stick with what's available in MVC. AOP isn't that widely used in .Net (or at least I don't think so).
Min