添加其他身份验证提供程序但保留当前会话数据 [英] Add Additional Authentication Provider but keep current session data

查看:15
本文介绍了添加其他身份验证提供程序但保留当前会话数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 .NET5 MVC 中有一个项目,它使用 实现了 Twitch 身份验证AspNet.Security.OAuth.Twitch.我配置了所有内容并且运行良好,但我想添加一个选项以将其他帐户与其他提供商(如 Twitter)相关联.我尝试使用 Microsoft.AspNetCore.Authentication.Twitter 添加 Twitter 身份验证.还配置了一切.

I have a project in .NET5 MVC that had implemented Twitch authentication using AspNet.Security.OAuth.Twitch. I configured everything and it is working fine, but I want to add the option to link an additional account with other providers, like Twitter. I tried to add Twitter authentication using Microsoft.AspNetCore.Authentication.Twitter. Also configured everything.

但是当我使用 Twitter 登录时,我当前的会话丢失了,来自 Twitch 的所有声明都被删除并替换为 Twitter 声明.我想这是预期的行为,但我不知道我是否可以保留这些声明或仅恢复 Twitter 声明而不存储在用户身份中(例如存储在数据库中).我的主要目标是使用 Twitch 身份验证作为登录应用程序的唯一方式,但必须选择链接其他提供商的帐户.

But when I login using Twitter, my current session is lost and all the Claims from Twitch were removed and replaced by Twitter Claims. I suppose that's the expected behaviour, but I don't know if I can keep those claims or only recover the Twitter Claims without storing in the User Identity (e.g. store in database). My main goal is to use Twitch authentication as the only way to login in the application but have to option to link accounts from other providers.

我在我的 Startup.cs 中添加了两个提供程序(最终可能会在将来的某个时间添加其他提供程序)

I have in my Startup.cs both providers added (and eventually maybe others added sometime in the future)

public void ConfigureServices(IServiceCollection services)
{
    // more stuff ...
    
    services.AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })
    .AddTwitch(options =>
    {
        options.ClientId = Configuration["Twitch-ClientId"];
        options.ClientSecret = Configuration["Twitch-ClientSecret"];
    })
    .AddTwitter(options =>
    {
        options.ConsumerKey = Configuration["Twitter-ConsumerKey"];
        options.ConsumerSecret = Configuration["Twitter-ConsumerSecret"];
    });
}

在我的 AuthController.cs 中,我有相应的挑战方法.

In my AuthController.cs I have the corresponding methods with the Challenge.

// Default Login using Twitch
[HttpGet("~/signin")]
public IActionResult Login() => RedirectToAction("Login", "Auth", new { provider = "Twitch" });

[HttpPost("~/signin")]
public IActionResult Login([FromForm] string provider)
{
     string redirect_uri = Url.Action("Index", "Home");

     return Challenge(new AuthenticationProperties() { RedirectUri = redirect_uri }, provider);
}

我不知道是否可以修改或配置 Challenge 以允许这种行为.我在 AuthenticationProperties<中没有看到任何属性/a> 可以使用的类.我最初尝试为其他提供程序创建另一个控制器/操作,但结果相同.

I don't know if Challenge can be modified or configured to allow this behaviour. I don't see any property in AuthenticationProperties class that can be used. I initially tried to create another Controller/Action for the additional providers but the results were the same.

任何帮助将不胜感激.

推荐答案

只要用户的会话 cookie 有效,您就可以使用多个身份验证方案对其进行身份验证并随时访问这些声明.

As long as the user's session cookies are valid, you can authenticate it with multiple auth schemes and access those claims anytime.

但是当我使用 Twitter 登录时,我当前的会话丢失了,来自 Twitch 的所有声明都被删除并替换为 Twitter 声明.

But when I login using Twitter, my current session is lost and all the Claims from Twitch were removed and replaced by Twitter Claims.

发生这种情况是因为您尝试使用 Cookie 方案来保存 Twitter 和 Cookie 的会话 cookie.抽搐.当您使用其中一个登录时,它会覆盖另一个.

This happens because you're trying to use Cookie scheme to hold the session cookie for both Twitter & Twitch. When you log in with one, it overwrites the other.

要解决此问题,您需要为每个单独的登录选项添加单独的 cookie.

To solve this, you need to add separate cookies for each individual login option.

services.AddAuthentication()
    .AddCookie("GoogleSession")
    .AddCookie("GithubSession")
    .AddGoogle(
        options => {
            // set the app credentials
            Configuration.GetSection("Google").Bind(options);
            // save session to this cookie
            options.SignInScheme = "GoogleSession";
        })
    .AddGitHub(
        options => {
            // set the app credentials
            Configuration.GetSection("Github").Bind(options);
            // save session to this cookie
            options.SignInScheme = "GithubSession";
        });

然后发出质询强制用户登录:

Then issue a challenge to force the user to login:

[AllowAnonymous]
[HttpGet("login-google")]
public ActionResult LoginGoogle()
{
    return Challenge(
        new AuthenticationProperties
        {
            RedirectUri = Url.Action("WhoAmI"),
        }, GoogleDefaults.AuthenticationScheme
    );
}

[AllowAnonymous]
[HttpGet("login-github")]
public ActionResult LoginGithub()
{
    return Challenge(
        new AuthenticationProperties
        {
            RedirectUri = Url.Action("WhoAmI"),
        }, GitHubAuthenticationDefaults.AuthenticationScheme
    );
}

然后在任何时候,您都可以对用户进行身份验证以阅读 &解析 cookie 以访问声明:

Then at anytime, you can authenticate the user to read & parse the cookie to access the claims:

[AllowAnonymous]
[HttpGet("me")]
public async Task<ActionResult> WhoAmI()
{
    var googleResult = await HttpContext.AuthenticateAsync(GoogleDefaults.AuthenticationScheme);
    if (googleResult.Succeeded)
    {
        var googlePrincipal = googleResult.Principal;
        // ... use google claims
        User.AddIdentity((ClaimsIdentity)googlePrincipal.Identity);
    }

    var githubResult = await HttpContext.AuthenticateAsync(GitHubAuthenticationDefaults.AuthenticationScheme);
    if (githubResult.Succeeded)
    {
        var githubPrincipal = githubResult.Principal;
        // ... use google claims
        User.AddIdentity((ClaimsIdentity)githubPrincipal.Identity);
    }

    return Ok(
        User.Identities.Select(
                id => new
                {
                    id.AuthenticationType, 
                    Claims = id.Claims.Select(c => new { c.Type, c.Value })
                }
            )
            .ToList()
    );

现在,当我访问 /me 时,我会得到所有会话的所有声明的列表:

Now when I visit /me, I get a list of all the claims from all the session:

[
  {
    "authenticationType": null,
    "claims": []
  },
  {
    "authenticationType": "Google",
    "claims": [
      {
        "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
        "value": "123131231231312123123123"
      },
      {
        "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
        "value": "My Fullname"
      },
      {
        "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname",
        "value": "MyName"
      },
      {
        "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname",
        "value": "MyLastname"
      },
      {
        "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
        "value": "my@gmail.com"
      }
    ]
  },
  {
    "authenticationType": "GitHub",
    "claims": [
      {
        "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
        "value": "1313123123"
      },
      {
        "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
        "value": "abdusco"
      },
      {
        "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
        "value": "my@email.com"
      },
      {
        "type": "urn:github:name",
        "value": "my name"
      },
      {
        "type": "urn:github:url",
        "value": "https://api.github.com/users/abdusco"
      }
    ]
  }
]

使用多种身份验证方案手动对用户进行身份验证有点繁琐.我们可以让 ASP.NET Core 为我们做.

It's a bit tedious to manually authenticate the user with multiple authentication schemes. We can let ASP.NET Core do it for us.

定义一个接受多个身份验证方案的授权策略.

Define an authorization policy that accepts multiple auth schemes.

services.AddAuthorization(
    options => options.DefaultPolicy = new AuthorizationPolicyBuilder(
            GoogleDefaults.AuthenticationScheme,
            GitHubAuthenticationDefaults.AuthenticationScheme
        ).RequireAuthenticatedUser()
        .Build()
);

现在,当您使用 [Authorize](并指定策略名称,如果需要)修饰操作时,HttpContext.User 将包含来自所有会话的身份和声明.

Now when you decorate an action with [Authorize] (and specify the policy name, if needed), HttpContext.User will contain both identities and claims from all sessions.

[Authorize]
[HttpGet("me")]
public async Task<ActionResult> WhoAmI()
{
    return Ok(
        // user has claims from all sessions
        User.Identities.Select(
                id => new
                {
                    id.AuthenticationType,
                    Claims = id.Claims.Select(c => new { c.Type, c.Value })
                }
            )
            .ToList()
    );
}

这与之前的输出相同,但没有样板.

This has the same output as before, but without the boilerplate.

这篇关于添加其他身份验证提供程序但保留当前会话数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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