Store data in cookie with asp.net core identity

2019-01-24 15:46发布

问题:

I'm using ASP.NET core identity with EF end I would like to store data related to the user in the authentication cookie.

This is how I used to do with ASP.NET 4.6 (appcontext is the data to store):

public static void IdentitySignin(AppContext appContext, string providerKey = null, bool isPersistent = false)
{
    var claims = new List<Claim>();

    // create *required* claims
    claims.Add(new Claim(ClaimTypes.NameIdentifier, appContext.UserId.ToString()));
    claims.Add(new Claim(ClaimTypes.Name, appContext.UserName));

    // serialized AppUserState object
    claims.Add(new Claim("appcontext" + EZA.Store.AppContext.Version, appContext.ToString()));

    var identity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);

    // add to user here!
    AuthenticationManager.SignIn(new AuthenticationProperties()
    {
        AllowRefresh = true,
        IsPersistent = isPersistent,
        ExpiresUtc = DateTime.UtcNow.AddDays(7),
    }, identity);
}

but now I'm using ASP.NET Identity with EF and I can't find a way to store some data in the cookie.

回答1:

Use AddClaimsAsync or AddClaimAsync of UserManager<YourUserIdentity>. for exemple like this when you sign in your user:

public class AccountController : Controller
{
    public UserManager<YourUserIdentity> UserManager { get; private set; }

    public SignInManager<YourUserIdentity> SignInManager { get; private set; }

    public AccountController(UserManager<YourUserIdentity> userManager, 
        SignInManager<YourUserIdentity> signInManager)
    {
        UserManager = userManager;
        SignInManager = signInManager;
    }

    public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
    {
        if (ModelState.IsValid)
        {
            var user = await UserManager.FindByNameAsync(model.UserName);

            await UserManager.AddClaimAsync(user, new Claim("your-claim", "your-value"));

            var signInStatus = await SignInManager.PasswordSignInAsync(user, model.Password, model.RememberMe, lockoutOnFailure: false);

            if (signInStatus.Succeeded)
                return RedirectToLocal(returnUrl);

            ModelState.AddModelError("", "Invalid username or password.");
            return View(model);
        }

        // If we got this far, something failed, redisplay form
        return View("Index", new LoginPageViewModel() { Login = model });
    }
 }


回答2:

Before i read @aqua's answer(i have learned this way just now), i would say that you have two options:

1 - Overriding UserClaimsPrincipalFactory like below:

public class AppClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>
{
    public AppClaimsPrincipalFactory(
        UserManager<ApplicationUser> userManager,
        RoleManager<IdentityRole> roleManager,
        IOptions<IdentityOptions> optionsAccessor) : base(userManager, roleManager, optionsAccessor)
    {
    }

    public async override Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
    {
        var principal = await base.CreateAsync(user);

        ((ClaimsIdentity)principal.Identity).AddClaims(new[] {
             new Claim("<claim name>", value)
        });

        return principal;
    }
}

// register it
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, AppClaimsPrincipalFactory>();

2- Using OnSigningIn event.

        services.Configure<IdentityOptions>(opt =>
        {
            opt.Cookies.ApplicationCookie.Events = new CookieAuthenticationEvents()
            {
                OnSigningIn = async (context) =>
                {
                    ClaimsIdentity identity = (ClaimsIdentity)context.Principal.Identity;
                    identity.AddClaim(new Claim("<claim name>", value));
                }
            };
        });