我可以通过使用 cookie 自动重新登录到我的 SignInManager 和 UserManager (Identity) -> Asp.Net-Core Identity (Deploye

Posted

技术标签:

【中文标题】我可以通过使用 cookie 自动重新登录到我的 SignInManager 和 UserManager (Identity) -> Asp.Net-Core Identity (Deployed live)【英文标题】:Can I automatically log back into my SignInManager and UserManager (Identity) via using cookies -> Asp.Net-Core Identity (Deployed live) 【发布时间】:2021-05-14 02:13:48 【问题描述】:

主要问题是:我可以通过使用 cookie 自动重新登录到我的 SignInManager 和 UserManager(身份)吗?如果这不可能,您会推荐什么替代方案?

所以,这里的主要问题归结为我的专用 IIS 池在 5 分钟后终止了工作程序;现在我可以将其配置为基于会话的,但由于它是共享服务器,这带来了一个全新的问题领域。 当工作人员被终止时,会话到期并且所有登录的用户都将注销。但是,我们仍然有 cookie。 值得注意的是,我的目标框架是“netcoreapp3.1”,并且该项目的部署是在实时服务器上。

让我们深入研究您需要了解的主要内容: 登录功能(路径:/Account/Login):

public async Task<IActionResult> Login(LoginViewModel model, string returnUrl)
           
        if (ModelState.IsValid)
        
            var result = await signInManager.PasswordSignInAsync(model.Username, model.Password, model.RememberMe, false);
            if (result.Succeeded)
            
                if (!string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl))
                
                    return Redirect(returnUrl);
                
                else
                
                    return RedirectToAction("Index", "Home");
                
            

            ModelState.AddModelError(String.Empty, "Invalid Login Attempt");
        
        return View(model);
    

接下来,相关的启动,在ConfigureServices中:

services.AddIdentity<ApplicationUser, IdentityRole>(options =>
         
             options.Password.RequiredLength = 3;
             options.Password.RequiredUniqueChars = 0;
             options.Password.RequireNonAlphanumeric = false;
             options.Password.RequireLowercase = false;
             options.Password.RequireUppercase = false;
             options.Password.RequireDigit = false;

         ).AddEntityFrameworkStores<AppDbContext>().AddDefaultTokenProviders();

services.ConfigureApplicationCookie(e =>
           
            e.LoginPath = new PathString("/Account/Login");
            e.LogoutPath = new PathString("/Account/Logout");
            e.AccessDeniedPath = new PathString("/Account/AccessDenied");
            e.Cookie.MaxAge = TimeSpan.FromDays(3);
            e.ExpireTimeSpan = TimeSpan.FromDays(3);
            e.Cookie.HttpOnly = true;
            e.SlidingExpiration = true;
            e.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
        );

在配置中:

app.UseAuthentication();

AddIdentity 默认调用 services.AddAuthentication(); 这将创建您的标准样板 Identity.Application Cookie,虽然会话不会终止或崩溃,但它会让您在 3 天内保持登录状态;自然地,因为我们的会话确实过期了,所以它会在 5 分钟内终止。那么,在开始时重申问题,是否可以使用我们拥有的 cookie 让用户保持登录(或重新登录),以便用户不会受到会话到期的不利影响?

那么,我在我想要部署的功能上是否存在根本缺陷,或者这是否可以通过一些工作来解决? 我遇到的很多“解决方案”都无法重新登录到 SignInManager/UserManager 或已被弃用。

这里的任何建议将不胜感激! :)

【问题讨论】:

你需要在IIS上延长worker的时间。 @YiyiYou 正如问题中提到的,我知道我可以扩展工作人员并将其更改为基于会话的系统,但是由于它是共享服务器,因此它有自己的一套复杂性,因此我正在寻找解决方案。我已经创建了一个解决方案,很快就会发布答案。 【参考方案1】:

现在我设法为此创建了一个解决方案,我首先要说的是,虽然它有效,但它有自己的一系列问题(主要是安全问题)。

值得说明的是,我已经有一个 ApplicationUser 设置,如果你没有,那么你需要创建它来扩展 IdentityUser 以将 cookieId 字段添加到你的身份数据库中。

第一步是为用户创建一种通过 cookie 登录到 signInManager 的方式,我们通过扩展 UserManager 类来实现这一点:

 public static class UserManagerExtensions

    public static async Task<ApplicationUser> FindByCookieAsync(this UserManager<ApplicationUser> um, string cookieId)
    
        return await um?.Users?.SingleOrDefaultAsync(x => x.CookieId.Equals(cookieId));
    

这允许我们检索我们将用来登录的 ApplicationUser。

下一步是设置这个 cookie,我们通过将以下代码应用到我们的登录和注册来做到这一点(如果您的注册自动登录用户):

var cookieVal = generateRandomCookieValue();
                HttpContext.Response.Cookies.Append("CookieName", cookieVal, new Microsoft.AspNetCore.Http.CookieOptions
                
                    Expires = DateTimeOffset.UtcNow.AddDays(7),
                    HttpOnly = true,
                    Secure = true,
                    SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax
                ) ;

                if (cookieVal != null)
                

                    ApplicationUser userModel = await userManager.FindByNameAsync(model.Username);
                    userModel.CookieId = cookieVal;
                    await userManager.UpdateAsync(userModel);
                

当用户注销时,我们只需从标头中删除此 cookie 并从数据库中清除存储的 cookie。这部分在我们的 Logout 方法中被调用:

 HttpContext.Response.Cookies.Delete("CookieName");
        ApplicationUser userModel = await userManager.FindByNameAsync(User.Identity.Name);
        userModel.CookieId = null;
        await userManager.UpdateAsync(userModel);

就个人而言,我在用户成功登录后使用此代码块。 由于我们没有在 cookie 中存储任何数据,而只是将其用作密钥,因此我们不需要复杂的 cookie,但我更喜欢模仿 Identity.Application cookie 的长度。

private string generateRandomCookieValue()
    
        StringBuilder returnString = new StringBuilder();
        Random rand = new Random();
        for (int i = 0; i < 646; i++)
        
            var x = rand.Next(48, 124);
            if((x<58 || x>64) && (x<91 || x > 96))
            
                if (x == 123)
                
                    returnString.Append('-');
                
                else if (x == 124)
                
                    returnString.Append('_');
                
                else
                
                    returnString.Append((char)x);
                
            
            else
            
                if (i != 0)
                
                    i--;
                
            
        
        return returnString.ToString();
    

现在我们在用户登录后的 1 周内创建了 cookie,我们需要一种方法来检查每个请求的状态,以使用户重新登录。 在我们的启动配置方法中,我们添加以下块:

app.Use(async (context, next) =>
        
            var cookie = context.Request.Cookies["CookieName"];
            var userAuth = context.User.Identity.IsAuthenticated;
            if (cookie != null && !userAuth)
            
                context.Request.Method = "POST";
                context.Request.Path = "/Account/AutoLogin";
            
            await next();
        );

        app.UseRouting();

我们需要添加“UseRouting()”方法才能使其工作。 我们正在使用此方法指向最后一步的 AutoLogin 方法。

[HttpPost]
    public async Task<IActionResult> AutoLogin()
    
        var cookie = HttpContext.Request.Cookies["CookieName"];
        var user = await userManager.FindByCookieAsync(cookie);
        if(user != null)
        
            await signInManager.SignInAsync(user, true);

            //If you want to configuring sliding expiration (which essentially issues a new cookie), you will need to manually do it here
            //Using the same setup we used in login, and then propagate that update to the database.
            var y = HttpContext;
            return RedirectToAction("Index", "Home");
        
        else
        
            HttpContext.Response.Cookies.Delete("CookieName");
            return RedirectToAction("Index", "Home");
                    
    

在我们的 autoLogin 方法中,我们可以通过创建一个新的 cookie 并在数据库中更新用户来手动创建一个滑动过期,这个过程类似于登录。

类似于会话,存在安全问题,如果你有用户的 cookie,你可以以他们的身份登录,我想不出用这个解决方案解决这个问题的方法,添加自定义滑动到期来发出新的 cookie 会稍微增加它。非常推荐安全连接。

我希望它有助于指导任何人为面临相同问题的人找到可能更好的解决方案。

【讨论】:

以上是关于我可以通过使用 cookie 自动重新登录到我的 SignInManager 和 UserManager (Identity) -> Asp.Net-Core Identity (Deploye的主要内容,如果未能解决你的问题,请参考以下文章

使用 JSONP 和 cookie 进行跨域登录

解决微信自动清除缓存,每天都需要重新登录

使用 Python 自动登录到我的本地网页

如何通过邮递员中的cookie传递会话ID并登录?

试图在我的反应应用程序中使用 cookie,但它一直被重新渲染

django:我们可以通过邮递员中的cookie通过会话ID并登录吗