Robert Paulsen
Robert Paulsen

Reputation: 5141

Custom IsInRole() when using Cookie Middleware without ASP.NET Identity

To maintain compatibility with existing applications I was planing on using Cookie Middleware without ASP.NET Identity, as described in the documentation:

https://docs.asp.net/en/latest/security/authentication/cookie.html

This seems to work as expected as far as logging a user in, but I'm having issues with roles -- specifically when using the [Authorize(Roles = "ADMIN")].

In the code below, I can call p.IsInRole("ADMIN") and my implementation of MyClaimsPrincipal.IsInRole() is called and returns true.

What doesn't work is the [Authorize(Roles = "ADMIN")] attribute because it ends up calling ClaimsPrincipal.IsInRole (which returns False) instead of MyClaimsPrincipal.IsInRole() (which returns True).

[Authorize(Roles = "ADMIN")]
public class MyAdminController : Controller
{
    public IActionResult Index()
    {
        var p = new MyClaimsPrincipal(ClaimsPrincipal.Current);

        bool isAdmin = p.IsInRole("ADMIN");

        return View();
    }
}
  1. When not using Identity and only using Cookie Middleware, can I use the [Authorize(Roles = "ADMIN")] attribute?

  2. How? :-)

If I had to guess, I'm not implementing p.IsInRole() correctly -- currently this method loads the roles, then returns a True/False. Perhaps I have to 'load' my roles elsewhere in such a way that the ClaimsPrincipal.IsInRole is sufficient. If I was using Identity(), I assume this would be an implementation of IUserRoleStore.

My other 'if i had to guess' answer is that somewhere in startup.cs I need to replace the current ClaimsPrincipal with an instance of MyClaimsPrincipal.

Thank you!

Upvotes: 3

Views: 861

Answers (1)

adem caglin
adem caglin

Reputation: 24063

You should add role claims when cookie is created.

In startup.cs:

app.UseCookieAuthentication(options =>
{
     options.AuthenticationScheme = "MyCookieMiddlewareInstance";
     options.LoginPath = new PathString("/Account/Login/");
     options.AccessDeniedPath = new PathString("/Account/Forbidden/");
     options.AutomaticAuthenticate = true;
     options.AutomaticChallenge = true;
 });

And login post method may be something like this(i assume that you have a custom login page):

[HttpPost]
public IActionResult Login(string userName, string password, string returnUrl)
{
     var user = _userService.GetUser(userName, password);// i assume that  _userService is injected
     if (user == null)
     {
          //return Error;
     }
     var claims = new List<Claim>()
     {
          new Claim(ClaimTypes.NameIdentifier, user.Id),
          new Claim(ClaimTypes.Name, user.GetFullName() ),
     };
     var identity = new ClaimsIdentity(claims, "Forms");
     identity.AddClaim(new Claim(ClaimTypes.Role, "ADMIN"));
     var principal = new ClaimsPrincipal(identity);

     HttpContext.Authentication.SignInAsync("MyCookieMiddlewareInstance", principal);
     return Redirect(returnUrl);
}

Upvotes: 4

Related Questions