asp.net核心身份提取并保存外部登录令牌并添加对本地身份的声明

nig*_*ige 8 asp.net authentication cookies claims-based-identity asp.net-identity-2

我是一个stackoverflow noob,所以如果我做错了,请放轻松.

我正在使用带有默认核心身份模板(本地帐户)的asp.net核心.

我已经加入了如何在本地登录时向用户主体添加声明的方式

[HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Login(LoginInputModel model)
    {
        if (ModelState.IsValid)
        {
            // This doesn't count login failures towards account lockout
            // To enable password failures to trigger account lockout, set lockoutOnFailure: true

            var user = await _userManager.FindByNameAsync(model.Email);

            await _userManager.AddClaimAsync(user, new Claim("your-claim", "your-value"));
Run Code Online (Sandbox Code Playgroud)

我已经弄清楚如何从外部登录返回索赔但我无法弄清楚如何在ExternalLoginCallback函数中创建用户主体之前添加这些索引

public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
    {
        if (remoteError != null)
        {
            ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}");
            return View(nameof(Login));
        }

        var info = await _signInManager.GetExternalLoginInfoAsync();
        if (info == null)
        {
            return RedirectToAction(nameof(Login));
        }
        else {
            // extract claims from external token here
        }

        // assume add claims to user here before cookie gets created??

        // Sign in the user with this external login provider if the user already has a login.
        var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false);
        if (result.Succeeded)
Run Code Online (Sandbox Code Playgroud)

我假设_signInManager.ExternalLoginSignInAsync函数的工作方式类似于本地登录_signInManager.PasswordSignInAsync,因为一旦调用它,就会创建cookie.但我不确定.

基本上我希望实现的是理解如何将自定义声明添加到创建的cookie中,而不管用户如何登录(本地或外部),以及如何在需要时将这些声明持久保存到数据库中.

我打算做一些工作,如果我使用google auth进行用户登录,我需要从google保存该access_token,因为我希望稍后使用它来调用Google API.因此,我需要能够将此access_token包含在已创建的用户主体中,并且我希望cookie可以对其进行声明,我也可以在前端使用.

这可能超出了这个问题的范围,但我也想在谷歌令牌到期时,对于某些人 - 如何使用刷新令牌并获得新的令牌,或强迫用户重新登录.

任何有关这方面的帮助都将非常受欢迎,我真的很难理解这一点,而不将此问题发布到stackoverflow.我已经阅读了很多有用信息的文章,但没有提供这个具体问题所要求的答案.所以非常感谢你提前.

干杯

Rui*_*Rui 8

当您使用await _userManager.AddClaimAsync(user, new Claim("your-claim", "your-value"));它实际更新Identity的aspnetuserclaims表.

无论何时登录(通过使用_signInManager.PasswordSignIn或_signInManager.ExternalLoginSignInAsync),都会读取该表中的声明,并将其添加到每个请求成为Principal的cookie中.

因此,您可能不希望在每次登录时都从UserManager调用AddClaimAsync方法.

关于外部登录提供程序,您可以在此处访问声明(在ExternalCallback和ExternalCallbackConfirmation中,如果您使用的是默认模板):

var info = await _signInManager.GetExternalLoginInfoAsync();
Run Code Online (Sandbox Code Playgroud)

索赔是在info.Principal.Claims.

默认情况下不包括访问令牌.如果是,它将在这里(以及类型和有效期):

var accessToken = info.AuthenticationTokens.Single(f => f.Name == "access_token").Value;
var tokenType = info.AuthenticationTokens.Single(f => f.Name == "token_type").Value;
var expiryDate = info.AuthenticationTokens.Single(f => f.Name == "expires_at").Value;
Run Code Online (Sandbox Code Playgroud)

要将访问令牌包含在AuthenticationTokens集合中,在配置GoogleAuthentication中间件时,请将SaveTokens标志设置为true:

        app.UseGoogleAuthentication(new GoogleOptions{
            ClientId = "...",
            ClientSecret = "...",
            SaveTokens = true
Run Code Online (Sandbox Code Playgroud)

现在,如果您想要控制cookie中的哪些声明,您必须"接管"创建声明主体的过程.

这是在您使用时为您完成的_signInManager.PasswordSignIn/ExternalLoginSignInAsync.

因此,例如,ExternalLoginSignInAsync替换:

var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false);
Run Code Online (Sandbox Code Playgroud)

附:

    var user =  await this._userManager.FindByLoginAsync(info.LoginProvider, info.ProviderKey);
    var claimsPrincipal = await this._signInManager.CreateUserPrincipalAsync(user);
    ((ClaimsIdentity)claimsPrincipal.Identity).AddClaim(new Claim("accessToken", info.AuthenticationTokens.Single(t => t.Name == "access_token").Value));
    await HttpContext.Authentication.SignInAsync("Identity.Application", claimsPrincipal);
Run Code Online (Sandbox Code Playgroud)

"Identity.Application"是默认的cookie名称.您可以在Startup的ConfigureServices方法中更改它,例如更改为MainCookie:

        services.Configure<IdentityOptions>(options => {
            options.Cookies.ApplicationCookie.AuthenticationScheme = "MainCookie";
        });
Run Code Online (Sandbox Code Playgroud)

您仍然需要ExternalCallbackConfirmation在AccountController中处理该操作.它将类似于上面的例子.