请考虑 program.cs 中的以下代码:
var builder = WebApplication.CreateBuilder(args);
//omit some builder settings
builder.Services.AddAuthentication(options =>
{
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
options.LoginPath = "/signin";
options.LogoutPath = "/signout";
})
.AddOAuth("Discord", options =>
{
options.AuthorizationEndpoint = "https://discord.com/api/oauth2/authorize";
options.Scope.Add("identify");
options.Scope.Add("email");
options.CallbackPath = new PathString("/Account/LoginCallback");
options.ClientId = "some id";
options.ClientSecret = "some secret";
options.TokenEndpoint = "https://discord.com/api/oauth2/token";
options.UserInformationEndpoint = "https://discord.com/api/users/@me";
options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
options.ClaimActions.MapJsonKey(ClaimTypes.Name, "username");
options.ClaimActions.MapJsonKey(ClaimTypes.Email, "email");
options.ClaimActions.MapCustomJson("urn:discord:avatar:url", user =>
string.Format(
CultureInfo.InvariantCulture,
"https://cdn.discordapp.com/avatars/{0}/{1}.{2}",
user.GetString("id"),
user.GetString("avatar"),
user.GetString("avatar")!.StartsWith("a_") ? "gif" : "png"));
options.AccessDeniedPath = "/Account/LoginFailed";
options.Events = new OAuthEvents
{
OnCreatingTicket = async context =>
{
var request = new HttpRequestMessage(HttpMethod.Get, context.Options.UserInformationEndpoint);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);
var response = await context.Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, context.HttpContext.RequestAborted);
var user = JsonDocument.Parse(await response.Content.ReadAsStringAsync()).RootElement;
context.RunClaimActions(user);
}
};
});
以下是我的帐户控制器内:
[HttpGet("~/signin")]
public async Task<IActionResult> SignIn() => View("SignIn", await HttpContext.GetExternalProvidersAsync());
[HttpPost("~/signin")]
public async Task<IActionResult> SignIn([FromForm] string provider)
{
if (string.IsNullOrWhiteSpace(provider))
{
return BadRequest();
}
if (!await HttpContext.IsProviderSupportedAsync(provider))
{
return BadRequest();
}
return Challenge(new AuthenticationProperties {RedirectUri = "/Account/LoginCallback" }, provider);
}
[HttpGet("~/signout")]
[HttpPost("~/signout")]
public IActionResult SignOutCurrentUser()
{
return SignOut(new AuthenticationProperties {RedirectUri = "/"},
CookieAuthenticationDefaults.AuthenticationScheme);
}
[HttpGet]
public IActionResult LoginCallback()
{
return RedirectToAction("Index", "Home");
}
上面的代码有效。会发生以下情况:
- 我点击 LoginViaDiscord 按钮
- 调用 SignIn post 方法
- 我被重定向到不和谐
- 我通过不和谐登录
- 我被重定向回 LoginCallback
当我查看网站时,我已经完全登录。问题是我跳过了记录用户并创建帐户的整个数据库步骤。
当我使用 MVC 5 进行类似的身份验证时,我将有一个回调操作方法,并且该回调方法将完成所有设置。创建用户,围绕用户执行逻辑,然后登录。但是,使用此代码,我已经完全登录,并且没有涉及数据库步骤。
我的问题是当挑战返回到 LoginCallback 时如何正确完成与上述相同但不登录的操作,以及如何从 LoginCallback 操作中的不和谐中检索信息?我想在允许用户登录之前对用户执行一些逻辑,并且我还想确保他们的帐户是在数据库中创建的。