如何在 aspnet 身份中进行会话管理?

Posted

技术标签:

【中文标题】如何在 aspnet 身份中进行会话管理?【英文标题】:How to do session management in aspnet identity? 【发布时间】:2015-12-29 01:49:40 【问题描述】:

我使用 Asp.net 身份 进行 登录、注册、忘记密码 等,源代码取自以下链接:

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.

现在我有 1 个表是 UserMaster 并且在注册期间我要求以下字段: 全名、EmailId、密码、联系人号码、性别

My UserMaster 包含以下字段:Id,FullName,EmailId,ContactNumber,Gender

现在,当用户提交注册表时,此 FullName、EmailId、ContactNumber、Gender 将与 Email、Password 一起保存在 UserMaster 中。

我的注册方法与以上2个链接中提供的相同。

在这里你可能会注意到 我的 UserMaster 和 AspnetUser 之间没有关系,所以在登录期间,当用户输入他的电子邮件 ID 登录时,我将使用这种方法 await SignInManager.PasswordSignInAsync 来验证用户,如果这样方法返回成功,然后我要做的是使用此电子邮件 ID 并在我的 UserMaster 中检查此电子邮件,并在哪里找到匹配项,我将从 UserMaster 获取该 UserId 并将其存储在会话中并在我的登录方法中使用我的应用程序,如下所示:

 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);
                
            

我在我的登录方法中谈论这个:

 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;
                            

这是一种合适的方式还是更好的方式,我想存储整个用户对象,而不仅仅是存储用户 ID。

那么谁能告诉我如何使用 aspnet 身份来做到这一点?

【问题讨论】:

你不喜欢内置的表单身份验证吗?您可以欺骗它并使其全部自定义但仍然利用该框架? (不过,我可能在您的代码中完全遗漏了一些东西)...查看这篇文章的答案:***.com/questions/1064271/… 最好将所有这些值存储在 AspNet Identity 使用的 ClaimsIdentity 中。这是相当标准的东西。 ***.com/questions/31974228/… @BrendanGreen:因此,我必须将其存储在声明身份中,而不是存储用户 ID 和所有其他信息,然后我将如何使用它?您能否发布任何我认为我将维护的登录方法的示例代码声明身份中的用户对象?请 这不是“必须”的问题,但恕我直言,这是一个更好的选择。开箱即用的 aspnet 身份体验具有针对 IIdentity 的方法扩展,例如,在控制器中您可以执行 User.Identity.GetUserId () 【参考方案1】:

由于您使用的是 Asp.Net Identity,因此您希望将与会话相关的内容存储为声明。这很容易通过自定义声明进行扩展。

顺便说一句,我认为您最好简单地扩展 ApplicationUser 以保存额外的数据,详细信息 here。

也就是说,这里有一个完整示例,说明如何将自定义声明类型添加到您的应用程序中。

第 1 步 - 定义一种或多种自定义声明类型以保存您的附加信息

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";

声明类型只是标识特定声明的唯一字符串。在这里,我们只是使用与内置声明类型类似的格式。

第 2 步 - 在登录过程中,为自定义声明类型设置值

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);

注意:我们使用自定义声明类型,以便保留现有的 NameIdentifierName 声明,因此可以轻松地从 Asp.Net Identity 我们的自定义 @ 访问身份信息987654327@表。

第 3 步 - 将扩展方法添加到 IIdentity,以便我们可以轻松访问我们的自定义声明数据

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;
    

这里没什么特别的。我们只是将IIdentity 转换为ClaimsIdentity,然后返回我们找到的给定CustomClaimType 的第一个声明的值,或者如果声明不存在,则返回null

第 4 步 - 现在我们可以非常轻松地在视图和/或控制器中访问我们的自定义声明数据。假设您想使用UserMaster 表中的全名而不是ApplicationUser?您现在可以这样做了:

<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>

您也可以在 Controller 中执行相同的操作。

【讨论】:

非常感谢您的回答。我一定会尝试这个并让您知道。再次感谢您为我节省宝贵的时间并发布此解决方案 @Brendan Green 在这中间,似乎这行代码 Session["UserId"] = fetchUSerId;似乎不再需要。是 bcoz Owin 在内部做的吗?我的意思是 Owin 是否会在内部创建一个 Session ?请在这里指导我。 @Brendan,我正在使用同样的东西,但遇到错误'userid is null' SignInAsync方法应该放在哪里? @ScottWeldon 这个方法位于SignInManager。您通常会创建自己的管理器,例如ApplicationSignInManager,您可以在其中使用 Brendan 的实现覆盖此方法。虽然我会避免这样做。在您的ApplicationUser 类中,有一个方法GenerateUserIdentityAsync。您还可以在此处设置自定义声明。【参考方案2】:

您可以添加为:

var listClaims=new[]  new Claims(ClaimsType.SerialNumber,Id), new Claims(ClaimsType.Name,FullName), new Claims(ClaimsType.HomePhone,ContactNumber), new Claims(ClaimsType.Gender,Gender);

var oAuthIdentity=new ClaimsIdentity(listClaims, otherparameter ...);

有关更多详细信息,您可以查看 System.Secutity.Claims.ClaimTypes

【讨论】:

【参考方案3】:

你可以这样做:

var fetchUser = context.UserMaster.Where(t => t.Email == model.Email).SingleOrDefault();
if (null == fetchUser)
    throw new Exception("Not found");
Session["User"] = fetchUser;

【讨论】:

我已经在我的代码中完成了这项工作。请正确查看我的代码。我要求为我在我的代码中发布的内容提供一个替代且良好的解决方案 对不起,您在我的解决方案中仅存储 userId 字段我存储所有用户对象。 请参阅 Brenden Green cmets

以上是关于如何在 aspnet 身份中进行会话管理?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 laravel 中进行会话?

如何在PHP中进行会话处理?

REST 购物车

在 php 中登录服务器端时在 android 中进行会话处理

如何管理 quickblox 会话 Javascript SDK

在php中进行会话检查后无法显示表