首页 文章

使用ASP.NET核心标识在Cookie中保存令牌

提问于
浏览
1

我想在我的'Identity'生成的cookie中保存一些东西 . 我目前正在使用文档中的默认身份设置 .

Startup.cs

services.Configure<IdentityOptions>(options =>
{
    // User settings
    options.User.RequireUniqueEmail = true;

    // Cookie settings
    options.Cookies.ApplicationCookie.AuthenticationScheme = "Cookies";
    options.Cookies.ApplicationCookie.ExpireTimeSpan = TimeSpan.FromHours(1);
    options.Cookies.ApplicationCookie.SlidingExpiration = true;
    options.Cookies.ApplicationCookie.AutomaticAuthenticate = true;
    options.Cookies.ApplicationCookie.LoginPath = "/Account";
    options.Cookies.ApplicationCookie.LogoutPath = "/Account/Logout";
});

AccountController.cs

var result = await _signInManager.PasswordSignInAsync(user.UserName, model.Password, true, true);

if (result.Succeeded)
{
    _logger.LogInformation(1, "User logged in.");

    var tokens = new List<AuthenticationToken>
    {
        new AuthenticationToken {Name = "Test", Value = "Test"},
    };


    var info = await HttpContext.Authentication.GetAuthenticateInfoAsync("Cookies");
    info.Properties.StoreTokens(tokens);

这似乎不起作用 . 因为还没有创建cookie . “Info”变量为空 .

我可以使用'CookieMiddleware'解决它

Startup.cs

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationScheme = "Cookies",
    ExpireTimeSpan = TimeSpan.FromHours(1),
    SlidingExpiration = true,
    AutomaticAuthenticate = true,
    LoginPath = "/Account",
    LogoutPath = "/Account/Logout",
});

但比我需要使用

await HttpContext.Authentication.SignInAsync("Cookies", <userPrincipal>);

在这种情况下,我需要为自己 Build 一个“用户主体” . 而且我更倾向于利用“身份”来解决这个问题 .

那有可能结合这个吗?如果不是这种情况,我该如何以良好的方式生成claimprincipal .

无需“映射”每个声明 .

List<Claim> userClaims = new List<Claim>
{
    new Claim("UserId", Convert.ToString(user.Id)),
    new Claim(ClaimTypes.Name, user.UserName),
    // TODO: Foreach over roles
};

ClaimsPrincipal principal = new ClaimsPrincipal(new ClaimsIdentity(userClaims));
await HttpContext.Authentication.SignInAsync("Cookies", principal);

所以类似于:

ClaimsPrincipal pricipal = new ClaimsPrincipal(user.Claims);

这不起作用,因为user.Claims的类型为IdentityUserClaim,而不是Security.Claims.Claim类型 .

谢谢阅读 . 祝你有美好的一天,

真诚的,布莱希特

1 回答

  • 2

    我设法解决了我的问题 .

    我写了'signInManager'中的相同功能 . 但添加我自己的身份验证属性 .

    var result = await _signInManager.PasswordSignInAsync(user, model.Password, true, true);
    if (result.Succeeded)
    {
        await AddTokensToCookie(user, model.Password);
        return RedirectToLocal(returnUrl);
    }
    if (result.RequiresTwoFactor)
    {
        // Ommitted
    }
    if (result.IsLockedOut)
    {
        // Ommitted
    }
    

    实际上在cookie中保存某些东西(令牌)的代码:

    private async Task AddTokensToCookie(ApplicationUser user, string password)
    {
        // Retrieve access_token & refresh_token
        var disco = await DiscoveryClient.GetAsync(Environment.GetEnvironmentVariable("AUTHORITY_SERVER") ?? "http://localhost:5000");
    
        if (disco.IsError)
        {
            _logger.LogError(disco.Error);
            throw disco.Exception;
        }
    
        var tokenClient = new TokenClient(disco.TokenEndpoint, "client", "secret");
        var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync(user.Email, password, "offline_access api1");
    
        var tokens = new List<AuthenticationToken>
        {
            new AuthenticationToken {Name = OpenIdConnectParameterNames.AccessToken, Value = tokenResponse.AccessToken},
            new AuthenticationToken {Name = OpenIdConnectParameterNames.RefreshToken, Value = tokenResponse.RefreshToken}
        };
    
        var expiresAt = DateTime.UtcNow + TimeSpan.FromSeconds(tokenResponse.ExpiresIn);
        tokens.Add(new AuthenticationToken
        {
            Name = "expires_at",
            Value = expiresAt.ToString("o", CultureInfo.InvariantCulture)
        });
    
        // Store tokens in cookie
        var prop = new AuthenticationProperties();
        prop.StoreTokens(tokens);
        prop.IsPersistent = true; // Remember me
    
        await _signInManager.SignInAsync(user, prop);
    }
    

    最后4行代码是最重要的代码 .

相关问题