2

I need to write some code to find an ID in my database of a Project. Users are coupled to a project and all the projects have a lot of connections to other objects, such as Sessions.

Now I need to check before running any Actions, if the user trying to access the Session, is connected to the same project as the session is connected to.

For this i want to use an [Attribute] on the Actions. MVC: creating a custom [AuthorizeAttribute] which takes parameters?

This question and answer got me started, but i'm having trouble using the constructor of the controller to get my Project ID

the goal is that i can write some code in each constructor, of all my controllers of objects depending on the Projects, find the project ID, and make it accessible (public), so my [customauthorize] will have access to this project ID to check whether the user has access or not.

My problem:

public class SessionController : Controller {

    NASDataContext _db = new NASDataContext();


    public SessionController() {
        var test = RouteData;
        var ses = _db.Sessies.First(q=>q.Ses_ID==1);
    }

How do I access my routedata? RouteData is null, HttpContext is null and Request is null.

I need the ID in the url, which is in the routedata...

Community
  • 1
  • 1
Stefanvds
  • 5,868
  • 5
  • 48
  • 72

2 Answers2

1

I would suggest placing this check in the Model rather than the Controller. In the Controller you'll need to decorate each action that requires this check, remember this is going execute code on every action you apply it to so you probably don't want to apply it at Controller level to start with. The simpler approach is to implement the check once in the Model then you have no 'concern' in your Controller for access rights. This will make the testing of this access right check possible as you'll only have the test in one place.

Lazarus
  • 41,906
  • 4
  • 43
  • 54
  • checking in the model. that's an interesting approach. how would one do that? do you have any lecture/examples? Would i write an extension method on the Model, or would I, like on an Edit Action GET request, change the LINQ code which gets the object, and add the filter there, which then will result in not finding the item, and would need some extra checks for a correct error message. – Stefanvds Jan 14 '11 at 12:26
  • It really comes down to how the Model is implemented. If you are just accessing Linq to SQL in your Controller actions then you've two basic approaches and one architectural approach. The first makes my advice moot and that's where you'd modify each and every instance of your code that accesses an object for which there is access control. The second is to use the fact that L2S objects are generated as partial and add the check into the Project object. The last is the best IMHO, implement the repository pattern and put the check in the repository. Much cleaner, testable and maintainable. – Lazarus Jan 14 '11 at 12:34
  • do you have any examples on that 2nd option? i have some objects which are 4lvls deep in the 'tree' that starts at projects. also different roles are coupled differently to a project. So if i get option 2 correct you'd add a method, which would take the current user as a parameter and return a bool, accessible or not? when i have this code (Module is child of Project) var mod = _db.Modules.First(m => m.Mod_ID == id); i then would call mod.Project.IsAccessible(User) ? is this the way you suggest to work? :) – Stefanvds Jan 14 '11 at 12:45
  • I don't have an example to hand, I tend to hand code my L2S objects from scratch. Off the top of my head I might extend the Module object with a method `bool IsAccessible(MembershipUser User)` (assuming that's the authentication method you are using) and then use `var mod = db.Modules.First(m => m.Mod_ID == id && m.IsAccessible(user));` – Lazarus Jan 14 '11 at 12:57
  • i'll give this a try but it probably will be `m.project.IsAccessible(user)` :) – Stefanvds Jan 14 '11 at 13:03
  • As i was afraid it gives me this error: `Method 'Boolean IsAccessible(System.Security.Principal.IPrincipal)' has no supported translation to SQL.` – Stefanvds Jan 14 '11 at 13:13
  • LOL Good old L2S. Let me have a play and I'll get back to you. – Lazarus Jan 14 '11 at 14:08
  • marked your idea as answer because you placed me on the right track ;) – Stefanvds Jan 14 '11 at 19:46
1

This is what i did now to fix it and i'm quite happy about it.

Module Partial:

public partial class Module {
    public string FullName {
        get {
            return Mod_Code + " " + Mod_Titel;
        }
    }
    public string ShortName {
        get {
            return Mod_Code;
        }
    }
    public bool IsAccessible() {
        return this.Projecten.IsAccessible();
    }
}

Projects Partial:

public partial class Projecten {
    public string FullName {
        get {
            if (Proj_Kortenaam == Proj_Naam)
                return Proj_Kortenaam;

            return Proj_Kortenaam + " " + Proj_Naam;
        }
    }
    public string ShortName {
        get {
            return Proj_Kortenaam;
        }
    }

    public bool IsAccessible() {
        return IsAccessible(HttpContext.Current.User);
    }

    public bool IsAccessible(IPrincipal user) {
        //this code checks if the user can access or not
        return MvcApplication.projectToegankelijk(user, this._Proj_ID);
    }
}

then in the Modules controller

    [NonAction]
    public ActionResult noRights() {
        ViewData["delError"] = "You have no rights.";
        return View("Error");
    }

    //
    // GET: /Modules/Details/5
    public ActionResult Details(int id) {
        var mod = _db.Modules.First(q => q.Mod_ID == id);
        if (mod.IsAccessible()) {
            return View(mod);
        }
        return noRights();
    }

I think this works pretty neat :)

Stefanvds
  • 5,868
  • 5
  • 48
  • 72