3

I am building a site that has Users that belong to an Account. The account is identified by an AccountId which is a foreign key for most data in the DB such as Charges (associated to an Account) or Receipts (associated to an Account).

Rather than hitting the DB every time the repository needs to be polled for data to get the user's AccountId, I wanted to add the AccountId as a claim. The goal being to do something like:

_repository.GetAllChargesByAccountId(User.Identity.GetAccountId());

I'm finding only tidbits and partial solutions for this and I haven't been able to resolve some differences between those examples and my specific environment (ASP.NET Core RC1, MVC 6, EF7).

I have derived a class from IdentityUser for adding attributes about the user:

public class UserIdentity : IdentityUser {
    public static object Identity { get; internal set; }
    public int AccountId { get; set; }
}

I have created a UserIdentityContext that derives from IdentityDbContext that I'm using for my EF user store.

And I have the following AuthController:

public class AuthController : Controller {
    private SignInManager<UserIdentity> _signInManager;

    public AuthController(SignInManager<UserIdentity> signInManager) {
        _signInManager = signInManager;
    }

    public IActionResult Login() {
        if (User.Identity.IsAuthenticated)
            return RedirectToAction("Dashboard", "App");

        return View();
    }

    [HttpPost]
    public async Task<ActionResult> Login(LoginViewModel vm, string returnUrl) {
        if (ModelState.IsValid) {
            var signInResult = await _signInManager.PasswordSignInAsync(vm.Username, vm.Password, true, false);
            if (signInResult.Succeeded) {
                if (String.IsNullOrWhiteSpace(returnUrl))
                    return RedirectToAction("Dashboard", "App");
                else return RedirectToAction(returnUrl);
            } else {
                ModelState.AddModelError("", "Username or password is incorrect.");
            }
        }   

        return View();
    }

    public async Task<IActionResult> Logout() {
        if (User.Identity.IsAuthenticated) {
            await _signInManager.SignOutAsync();
        }

        return RedirectToAction("Index", "App");
    }
}

Looking at other posts, it sounds like I need to add an IdentityExtension in order to access the claim as User.Identity.GetAccountId() and generate a custom user identity as in this answer: How to extend available properties of User.Identity but obviously this is done in an older version and many of the method calls are not applicable anymore.

Thanks in advance for any answers or guidance.

Community
  • 1
  • 1
John Yost
  • 693
  • 5
  • 20
  • seems very similar to this question http://stackoverflow.com/questions/36496135/store-custom-datas-in-identity-cookie/36498357#36498357 – Joe Audette Apr 24 '16 at 10:55

1 Answers1

0

if you have added a claim for AccountId you can then easily write an extension method to get it:

public static string GetAccountId(this ClaimsPrincipal principal)
{
    if (principal == null)
    {
        throw new ArgumentNullException(nameof(principal));
    }
    var claim = principal.FindFirst("AccountId");
    return claim != null ? claim.Value : null;
}

if you need help on how to add a custom claim see this question

Community
  • 1
  • 1
Joe Audette
  • 35,330
  • 11
  • 106
  • 99
  • Thanks Joe. The extension looks like the easy part. Let me look at the questions you referenced to see if they solve the claim part. The gap I see immediately is that the first questions creates a claim but assigns it a generic value of "true". For me, I need to assign a value that's unique to each user, the AccountId. So I need to pull that from the user repository but not sure how to get to that from the ClaimsTransform class. – John Yost Apr 24 '16 at 23:25
  • One thing I notice immediately is that using TransformClaims defeats the purpose since it doens't store any additional attributes in the cookie. It would still require a DB hit to get the AccountId on every request. I'll try overriding the ClaimsFactory instead. – John Yost Apr 25 '16 at 00:35
  • Did you get sorted on this? Looking to do the same! – P456678 Aug 15 '17 at 20:08