asp.net 核心身份提取并保存外部登录令牌并向本地身份添加声明 [英] asp.net core identity extract and save external login tokens and add claims to local identity

查看:29
本文介绍了asp.net 核心身份提取并保存外部登录令牌并向本地身份添加声明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am a stackoverflow noob so please go easy if I am doing this wrong.

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

I am using asp.net core with the default core identity template (local accounts).

我已经确定了如何在用户像这样在本地登录时向用户主体添加声明

I have accertained how to add claims to user principal when they login locally like so

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

而且我已经弄清楚如何从外部登录返回声明,但我不知道如何在 ExternalLoginCallback 函数中创建用户主体之前添加这些声明

And I have figured out how to get claims returned from the external login but I cannot figure out how I would add these before the user principal gets created in the ExternalLoginCallback function

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)

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

I am assuming the the _signInManager.ExternalLoginSignInAsync function works similar to the local login _signInManager.PasswordSignInAsync in the sense that once it is called, the cookie will be created. But I am just not sure.

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

Essentially what I am hoping to achieve, is understanding of how to add custom claims into the cookie that gets created regardless of how to user logins in (local or external), and how to persist these claims to the database if required.

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

I am planning on doing some work where if I have a user login using say google auth, I need to save that access_token from google, because I wish to call into the Google APIs later with it. So I need to be able to include this access_token in with the User Principal that gets created, and I would hope the cookie would have a claim on it I could use at the front end as well.

这可能超出了这个问题的范围,但我也想在 google 令牌过期时,以某种方式使用刷新令牌并获取新令牌,或强制用户重新登录.

This might be out of scope on this question but I would also like when the google token expires, for some-how it to use the refresh token and go get a new one, or force the user to relogin.

对此的任何帮助将不胜感激,我真的很努力地理解这一点,而没有将此问题发布到 stackoverflow.我已经阅读了许多包含大量有用信息的文章,但没有提供这个特定问题所要求的答案.非常感谢您.

Any help on this would be super appreciated, I have really tried hard to understand this without posting this question to stackoverflow. I have read many articles with lots of useful info, but does not provide the answers this specific question is asking. So Thank you very much in advance.

干杯

推荐答案

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

When you use await _userManager.AddClaimAsync(user, new Claim("your-claim", "your-value")); that actually updates the Identity's aspnetuserclaims table.

每当您登录时(通过使用 _signInManager.PasswordSignIn 或 _signInManager.ExternalLoginSignInAsync),系统都会读取该表中的声明并将其添加到 cookie 中,该 cookie 在每个请求中都会成为主体.

Whenever you sign in (by using _signInManager.PasswordSignIn or _signInManager.ExternalLoginSignInAsync) the claims from that table are read and added to the cookie that on every request becomes the Principal.

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

So you probably don't want to be calling the AddClaimAsync method from UserManager on every login.

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

Regarding external login providers, you have access to the claims when you call (in ExternalCallback and ExternalCallbackConfirmation if you are using the default templates) here:

var info = await _signInManager.GetExternalLoginInfoAsync();

声明在 info.Principal.Claims 中.

默认情况下不包含访问令牌.当它是时,它会在这里(连同类型和到期日期):

The access token is not included by default. When it is, it will be here (along with the type and expiry date):

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;

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

To have the access token be included in the AuthenticationTokens collection, when you are configuring the GoogleAuthentication middleware set the SaveTokens flag to true:

        app.UseGoogleAuthentication(new GoogleOptions{
            ClientId = "...",
            ClientSecret = "...",
            SaveTokens = true

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

Now, if you want to have control over which claims go in the cookie you have to "take over" the process of creating the claims principal.

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

This is done for you when you use _signInManager.PasswordSignIn/ExternalLoginSignInAsync.

例如,对于 ExternalLoginSignInAsync 替换:

var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false);

与:

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

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

"Identity.Application" is the default cookie name. You can change it in Startup's ConfigureServices method, for example to MainCookie:

        services.Configure<IdentityOptions>(options => {
            options.Cookies.ApplicationCookie.AuthenticationScheme = "MainCookie";
        });

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

You still need to handle the ExternalCallbackConfirmation action in the AccountController. It will be similar to the example above.

这篇关于asp.net 核心身份提取并保存外部登录令牌并向本地身份添加声明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆