How would I mimic User.IsInRole()
Asked Answered
G

4

6

I have a website thats build with VS 2012 Internet Application ( Simple membership) EF Code First

Updates

I would like to know how to extend HttpContext.User.IsInRole(role) 's functionality for a custom table -> User.IsInClient(client).

Grooms answered 21/8, 2013 at 20:0 Comment(4)
bump.... A way to create a new Class that does this functionality maybe? Then to be able to call the class from the View or Controller as needed.. ?Grooms
Can you explain it better? What is Users.InRoles("Admin")? Where can it be found? Is it inside framework or is it your custom thing? Maybe you are asking about HttpContext.User.IsInRole(role) and a way to extend this functionality to HttpContext.User.IsInClient(client) instead?Management
@JaroslawWaliszko Updated the question, that makes alot more sence to ask it this way.Grooms
Ok, let me help you then in a moment.Management
M
15

Here is the way I'd suggest to solve your issue:

Create your own interface which implements System.Security.Principal, where you could place any methods you need:

public interface ICustomPrincipal : IPrincipal
{
    bool IsInClient(string client);
}

Implement this interface:

public class CustomPrincipal : ICustomPrincipal
{
    private readonly IPrincipal _principal;

    public CustomPrincipal(IPrincipal principal) { _principal = principal; }

    public IIdentity Identity { get { return _principal.Identity; } }
    public bool IsInRole(string role) { return _principal.IsInRole(role); }

    public bool IsInClient(string client)
    {
        return _principal.Identity.IsAuthenticated 
               && GetClientsForUser(_principal.Identity.Name).Contains(client);
    }

    private IEnumerable<string> GetClientsForUser(string username)
    {
        using (var db = new YourContext())
        {
            var user = db.Users.SingleOrDefault(x => x.Name == username);
            return user != null 
                        ? user.Clients.Select(x => x.Name).ToArray() 
                        : new string[0];
        }
    }
}

In the Global.asax.cs assign your custom principal to the request user context (and optionally to the executing thread if you plan to use it later). I suggest to use Application_PostAuthenticateRequest event not Application_AuthenticateRequest for this assignment, otherwise your principal will be overridden (at least by ASP.NET MVC 4):

protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
    Context.User = Thread.CurrentPrincipal = new CustomPrincipal(User);

    /* 
     * BTW: Here you could deserialize information you've stored earlier in the 
     * cookie of authenticated user. It would be helpful if you'd like to avoid 
     * redundant database queries, for some user-constant information, like roles 
     * or (in your case) user related clients. Just sample code:
     *  
     * var authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
     * var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
     * var cookieData = serializer.Deserialize<CookieData>(authCookie.UserData);
     *
     * Next, pass some deserialized data to your principal:
     *
     * Context.User = new CustomPrincipal(User, cookieData.clients);
     *  
     * Obviously such data have to be available in the cookie. It should be stored
     * there after you've successfully authenticated, e.g. in your logon action:
     *
     * if (Membership.ValidateUser(user, password))
     * {
     *     var cookieData = new CookieData{...};         
     *     var userData = serializer.Serialize(cookieData);
     *
     *     var authTicket = new FormsAuthenticationTicket(
     *         1,
     *         email,
     *         DateTime.Now,
     *         DateTime.Now.AddMinutes(15),
     *         false,
     *         userData);
     *
     *     var authTicket = FormsAuthentication.Encrypt(authTicket);
     *     var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, 
                                           authTicket);
     *     Response.Cookies.Add(authCookie);
     *     return RedirectToAction("Index", "Home");
     * }
     */         
}

Next, to be able to use the property User from HttpContext in the controller without casting it to ICustomPrincipal each time, define base controller where you override the default User property:

public class BaseController : Controller
{
    protected virtual new ICustomPrincipal User
    {
        get { return (ICustomPrincipal)base.User; }
    }
}

Now, let other controllers inherit from it:

public class HomeController : BaseController
{
    public ActionResult Index()
    {
        var x = User.IsInClient(name); 

If you use Razor View Engine, and you'd like to be able to use your method in the very similar way on the views:

@User.IsInClient(name)

you need to redefine WebViewPage type:

public abstract class BaseViewPage : WebViewPage
{
    public virtual new ICustomPrincipal User
    {
        get { return (ICustomPrincipal)base.User; }
    }
}

public abstract class BaseViewPage<TModel> : WebViewPage<TModel>
{
    public virtual new ICustomPrincipal User
    {
        get { return (ICustomPrincipal)base.User; }
    }
}

and tell Razor to reflect you changes, by modifying appropriate section of the Views\Web.config file:

<system.web.webPages.razor>
    ...
    <pages pageBaseType="YourNamespace.BaseViewPage">
Management answered 9/9, 2013 at 14:41 Comment(8)
WebviewPage class just any random class or how should i define it?Grooms
@Don Thomas Boyle: WebViewPage is legitimate framework class from System.Web.Mvc namespace.Management
Okay so we're just overriding the Already existing but non viewable WebViewPage Class?Grooms
Sorry just some follow up questions so i can understand the Principle of the Answer fully and learn from it, A1 btw and answered.Grooms
@Don Thomas Boyle: What do you mean by "non viewable"? WebViewPage type represents the properties and methods that are needed in order to render a view that uses ASP.NET Razor syntax (msdn.microsoft.com/en-us/library/gg402107(v=vs.108).aspx). You'll be able to use your custom typed User object on the views by overriding this class and pointing Razor in the web.config to use it, instead the default one.Management
What i ment by "non viewable", and sorry for the misunderstanding, is that you cannot see the source code, therefor the overriding of the properties and methods instead of manipulating the already written code. I am new enough to not know how to properly use terminology. Sorry and Thanks the link cleared it up.Grooms
@Don Thomas Boyle: N/P. You'll just get intelisense support by doing that and the simplicity of usage, as Razor will be aware of your type. So instead of @(((ICustomPrincipal)User).IsInClient(...)), enough will be: @User.IsInClient(...).Management
@Don Thomas Boyle: I've added information of how to store/assign some data of authenticated user in the cookie, if you'd like to avoid redundant database queries in your custom IPrincipal implementation.Management
C
0

Use Linq:

var Users = Membership.GetAllUsers();

//**Kinda Like Users.InCLients(userName).
var users = from x in Users 
              join y in db.Clinets on x.ProviderUserKey equals y.UserID
              select x

//**Kinda Like Clients.InUsers(userName)
var clients = from x in db.Clinets
              join y in Users on x.UserID equals y.ProviderUserKey
              select x
Canteen answered 21/8, 2013 at 20:17 Comment(4)
wouldn't it be 2 joins since we have 3 tables? Users Clients UserInCleints ( holds 2 id's of User and of Client). But the membership.getallusers() is neet. I like the concept so farGrooms
@DonThomasBoyle if you have UserInCleints table you can join it instead of Users table.Canteen
Yeah but that only gives me Id's back , I would want the Names and other information associated with those id's.Grooms
@DonThomasBoyle If you need all data, than you may use join as it is shown in example. In that case you don't need UserInCleints table at all. Or you may extend your UserInCleints table to get more data than just an UserID.Canteen
H
-1

try this way

List<Clinets> AllClinets =entityObject.Clinets .ToList();

Foreach( var check in AllClinets)
{
  if(check.UserTable.RoleTable.RoleName=="Rolename1")
   {
      //This users are Rolename1 
   }
  else
   {
   //other.
   }
}
Horripilation answered 22/8, 2013 at 3:33 Comment(1)
I think you mis-understood, I'm trying to re-create the method of InRoles for InClients for 2 very seperate models and methods, there are no helpers or classes in place for this.Grooms
L
-2

Stored procedure would be better in this case.

Lead answered 4/9, 2013 at 5:42 Comment(1)
sorry but that makes no sense at all -1.Grooms

© 2022 - 2024 — McMap. All rights reserved.