Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do session management in aspnet identity?

I am using Asp.net identity for Login,Register,Forgot Password etc and source code is taken from this below link:

http://www.asp.net/mvc/overview/security/create-an-aspnet-mvc-5-web-app-with-email-confirmation-and-password-reset

http://www.asp.net/identity/overview/features-api/account-confirmation-and-password-recovery-with-aspnet-identity.

Now i have 1 table that is UserMaster and during registration i am asking for this following fields: FullName,EmailId,Password,ContactNumber,Gender.

My UserMaster Contains this following fields:Id,FullName,EmailId,ContactNumber,Gender

Now when user will submit registration form this FullName,EmailId,ContactNumber,Gender will be saved in UserMaster along with the Email,Password will be saved in AspnetUser.

My Register Method is same as provided in above 2 links.

Here you might notice that there is no relationship between my UserMaster and AspnetUser so during login when user will enter his email id to login i will use this method await SignInManager.PasswordSignInAsync to verify user and if this method returns success then what i will do is use this email id and check this email in my UserMaster and where match will be found i will fetch that UserId from UserMaster and store it in session and use thorugh out my application in my login method like below:

 public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
            {
                if (!ModelState.IsValid)
                {
                    return View(model);
                }

                // This doesn't count login failures towards account lockout
                // To enable password failures to trigger account lockout, change to shouldLockout: true
                var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
                switch (result)
                {
                    case SignInStatus.Success:
                  using (var context = new MyEntities())
                        {
                            var fetchUSerId = context.UserMaster.Where(t => t.Email == model.Email).Select(t=>t.UserId).SingleOrDefault();
                            Session["UserId"] = fetchUSerId;
                        }
                        return RedirectToLocal(returnUrl);
                    case SignInStatus.LockedOut:
                        return View("Lockout");
                    case SignInStatus.RequiresVerification:
                        return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
                    case SignInStatus.Failure:
                    default:
                        ModelState.AddModelError("", "Invalid login attempt.");
                        return View(model);
                }
            }

I am talking about this in my login method:

 case SignInStatus.Success:
                      using (var context = new MyEntities())
                            {
                                var fetchUSerId = context.UserMaster.Where(t => t.Email == model.Email).Select(t=>t.UserId).SingleOrDefault();
                                Session["UserId"] = fetchUSerId;
                            }

Is this an appropriate way or still a better way and i want to store entire user object instead of just storing User Id.

So can anybody tell me how to do this with aspnet identity??

like image 239
Learning-Overthinker-Confused Avatar asked Oct 01 '15 05:10

Learning-Overthinker-Confused


People also ask

How session management is done in MVC?

ASP.NET MVC provides three ways (TempData, ViewData and ViewBag) to manage session, apart from that we can use session variable, hidden fields and HTML controls for the same.


1 Answers

Since you are using Asp.Net Identity, you want to store session related stuff as claims. This is very easy to extend with customised claims.

As an aside, I think you'd be better off simple extending ApplicationUser to hold the additional data, as detailed here.

That said, here is a complete example of how to add custom claim types to your application.

Step 1 - Define one or more custom claim types to hold your additional information

public static class CustomClaimTypes
{
    public const string MasterFullName = "http://schemas.xmlsoap.org/ws/2014/03/mystuff/claims/masterfullname";
    public const string MasterUserId = "http://schemas.xmlsoap.org/ws/2014/03/mystuff/claims/masteruserid";
}

A claim type is just a unique string that identifies the specific claim. Here we are just using a similar format as the built in claim types.

Step 2 - During the sign in process, set values for the custom claim types

private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
    AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
    var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);

    //Fetch data from the UserMaster table 
    var userdata = GetdatafromUserMaster();

    //Using the UserMaster data, set our custom claim types
    identity.AddClaim(new Claim(CustomClaimTypes.MasterUserId, userdata.UserId));
    identity.AddClaim(new Claim(CustomClaimTypes.MasterFullName, userdata.FullName));

    AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}

Note: we are using custom claim types so that we preserve the existing NameIdentifier and Name claims, and can therefore easily access identity information from both Asp.Net Identity and our custom UserMaster table.

Step 3 - Add extension method(s) to IIdentity so we can easily access our custom claim data

public static class IdentityExtensions
{
    public static string GetMasterUserId(this IIdentity identity)
    {
        if (identity == null)
            return null;

        return (identity as ClaimsIdentity).FirstOrNull(CustomClaimTypes.MasterUserId);
    }

    public static string GetMasterFullName(this IIdentity identity)
    {
        if (identity == null)
            return null;

        return (identity as ClaimsIdentity).FirstOrNull(CustomClaimTypes.MasterFullName);
    }

    internal static string FirstOrNull(this ClaimsIdentity identity, string claimType)
    {
        var val = identity.FindFirst(claimType);

        return val == null ? null : val.Value;
    }
}

Nothing fancy here. We just cast the IIdentity as a ClaimsIdentity and then return the value of either the first claim of the given CustomClaimType that we find, or we return null if a claim doesn't exist.

Step 4 - Now we can access our custom claim data in views and/or controllers really easily. Say you wanted to use the full name from your UserMaster table instead of the ApplicationUser? You can now do this:

<ul class="nav navbar-nav navbar-right">
    <li>
        @Html.ActionLink("Hello " + User.Identity.GetMasterFullName() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
    </li>
    <li><a href="javascript:document.getElementById('logoutForm').submit()">Log off</a></li>
</ul>

You can also do the same thing from within a Controller.

like image 84
Brendan Green Avatar answered Sep 22 '22 09:09

Brendan Green