只要用户的会话 cookie 有效,您就可以使用多个身份验证方案对其进行身份验证并随时访问这些声明。
但是当我使用 Twitter 登录时,我当前的会话丢失了,所有来自 Twitch 的声明都被删除并被 Twitter 声明所取代。
发生这种情况是因为您尝试使用Cookie
方案来保存 Twitter 和 Twitch 的会话 cookie。当您使用其中一个登录时,它会覆盖另一个。
要解决此问题,您需要为每个单独的登录选项添加单独的 cookie。
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";
});
然后发出一个挑战来强制用户登录:
[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 以访问声明:
[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
,我得到了所有会话中所有声明的列表:
[
{
"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 为我们做这件事。
定义一个接受多个身份验证方案的授权策略。
services.AddAuthorization(
options => options.DefaultPolicy = new AuthorizationPolicyBuilder(
GoogleDefaults.AuthenticationScheme,
GitHubAuthenticationDefaults.AuthenticationScheme
).RequireAuthenticatedUser()
.Build()
);
[Authorize]
现在,当您使用(并指定策略名称,如果需要)装饰操作时,HttpContext.User
将包含所有会话的身份和声明。
[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()
);
}
这与以前的输出相同,但没有样板。