Search code examples
vue.jsasp.net-coreasp.net-core-mvcasp.net-identity

Storing a UserID in ASP.NET Core with partial Identity Framework


I have created a log in functionality using identity frameworks persistent cookie (if user selects remember me) or a session cookie if just a standard log on and no remember me is ticked. I use the following code:

                        var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);

                    if (RememberMe)
                    {
                        await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
                            new ClaimsPrincipal(claimsIdentity),
                            new AuthenticationProperties
                            {
                                IsPersistent = RememberMe,
                                ExpiresUtc = DateTimeOffset.UtcNow.AddHours(2)
                            });
                    }
                    else
                    {
                        await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
                            new ClaimsPrincipal(claimsIdentity));
                    }
                    return RedirectToPage("/index");

I use VueJS for my front end so I make various axios POST requests to my SQL server so I setup a controller to handle this as shown in the example below:

        [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult AddFirm([FromBody] FirmModel model)
    {

        String query = "exec dbo.A2Q_Edit_0112_RR_UploadNewReview_AddFirm @FIRM_NAME, @USER_ID";
        System.Diagnostics.Debug.WriteLine("value:" + model.FIRM_NAME);
        using (var connection = new SqlConnection(connectionString))
        {
            var json = connection.QuerySingle<string>(query, new { FIRM_NAME = model.FIRM_NAME , USER_ID = USER_ID});
            return Content(json, "application/json");
        }

    }

As you will see my controller includes a parameter in my SQL queries to capture the UserID of who initiated the stored procedure. I would like to store this variable server side. I have read numerous posts and it seems many people hint at identity to handle this because sessions is not reliable to store user data. Therefore, I am curious how can I use Identity for this when I am only using a limited version of identity to make the cookies. I do not need all the overhead of identity and the tables, etc. Is there a way to use identity to store these user variables similar to session? If not is there a secure way to use this cookie to store the user ID or act as the user ID? Or given my description would session be best in this modern age with ASP.NET Core 3.1 and IIS 8?

This seems like a simple thing to do but I am struggling with this one aspect to keep this User ID variable in my sql query parameter filled without storing on the frontend in VueJS.

*caveat I may use signalIR in the future so that may cancel out session as an option from my understanding for posts I’ve seen on stack.


Solution

  • If I get your question right, that we want some kind of mechanism to get UserId for every request.

    If that so, consider to put the UserId into the cookie, It's not something that's need to be secure as even jwt token have a sub key intend to hold some kind of value like this.

    As using with default .AddCookie extension in ASP net, your login process should be

    // Create the claims
    var claims = new List<Claim>
    {
        new Claim(ClaimTypes.NameIdentifier, [The UserId goes here]),
        // some other require stuff
    };
    
    // Sign in
    var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
    await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
        new ClaimsPrincipal(claimsIdentity),
        new AuthenticationProperties
        {
            IsPersistent = RememberMe,
            ExpiresUtc = DateTimeOffset.UtcNow.AddHours(2)
        });
    

    Now,userId was stored inside the cookie, don't try to decrypt it, this is an example form of the cookie content after generated CfDJ8MblQARvMeFAppYZW16O0Qm0moCi0%2Fu77SujBcwhrmg2gAtPiCrKJEcAL3Ry%2By9Xp8subrazS5ajc%2F4dD153VZrndwSU3dVXmESF0NZxW8oWmyo5lhuGSv9LpgAuQs6pEfRJCeLXpE4%2FxU9SDzyWlk4LLf9HzxiBXTYswPZdvnLr

    And for which ever request that got attached with the cookie. We can get userId back from User as a property of HttpContext.

    public IActionResult Index()
    {
        var user = HttpContext.User.FindFirst(ClaimTypes.NameIdentifier);
        var myUserId = user.Value;
        // Then pass it along as wished
    }
    

    About using SignalR: Is that you mean log the user out ? If so signalR can handle happy cases, as long as the app still have enough connection (webSocket hold it, careful, imagine about just 3-500 CCU or more, just for this sometime task ? and even when connection got drop and re-connect, you still have to deal with that logic).

    Instead, why don't attach an unique key to the cookie when you log-in, that re-presented for each log-in session. Then have a middleware to check if that key is exists from a black list(which storing as cache would be nice), which we will throw every seesion need to lock out here (expired as long as cookie life time, which in this case, 2 hours).

    Done, no more connection holding, no more happy-unhapply cases and all those complexities stuff that come with websocket.