自定义RemoteAuthenticationHandler无法实现登录的问题求助
问题分析
你当前的实现缺少外部认证流程中关键的认证属性传递和Identity外部登录的回调衔接,导致点击登录按钮后无法触发后续的本地账号关联流程。具体问题点:
HandleChallengeAsync直接硬编码跳转,丢失了Identity传递的returnUrl、state等关键认证属性- 自定义登录页的表单没有携带这些必要属性,回调到
/signin-myauth时无法完成认证上下文的衔接 HandleRemoteAuthenticateAsync没有关联原有的AuthenticationProperties,导致认证成功后无法正确跳转到目标页面并触发Identity的外部登录逻辑
修复步骤
1. 修改HandleChallengeAsync,传递认证属性
更新MyAuthHandler中的HandleChallengeAsync方法,将原有的认证属性编码后传递到自定义登录页:
using Microsoft.AspNetCore.WebUtilities; // ... protected override Task HandleChallengeAsync(AuthenticationProperties properties) { // 将认证属性编码为查询参数 var query = QueryHelpers.AddQueryString("/my-sign-in-page", properties.Items); // 添加returnUrl参数(如果存在) if (!string.IsNullOrEmpty(properties.RedirectUri)) { query = QueryHelpers.AddQueryString(query, "returnUrl", properties.RedirectUri); } Context.Response.Redirect(query); return Task.CompletedTask; }
2. 更新自定义登录页,携带认证属性
修改MySignInPage.razor,接收并在表单中携带state和returnUrl等属性:
@page "/my-sign-in-page" @code { [SupplyParameterFromQuery] public string? state { get; set; } [SupplyParameterFromQuery] public string? returnUrl { get; set; } } <form action="/signin-myauth" method="post"> @if (!string.IsNullOrEmpty(state)) { <input type="hidden" name="state" value="@state" /> } @if (!string.IsNullOrEmpty(returnUrl)) { <input type="hidden" name="returnUrl" value="@returnUrl" /> } <button type="submit">Click here to sign in</button> </form>
3. 完善HandleRemoteAuthenticateAsync,关联认证属性
更新HandleRemoteAuthenticateAsync方法,从请求中获取state和returnUrl,并关联到AuthenticationTicket的属性中:
protected override Task<HandleRequestResult> HandleRemoteAuthenticateAsync() { // 从请求中获取state和returnUrl参数 var state = Request.Form["state"].FirstOrDefault(); var returnUrl = Request.Form["returnUrl"].FirstOrDefault(); // 创建包含跳转信息的认证属性 var properties = new AuthenticationProperties { RedirectUri = returnUrl, Items = { ["state"] = state } }; // 创建身份凭证 var nameIdentifierClaim = new Claim(ClaimTypes.NameIdentifier, "mrpmorris@gmail.com", ClaimTypes.NameIdentifier, "myauth", "myauth"); var identity = new ClaimsIdentity([nameIdentifierClaim], "myauth"); var principal = new ClaimsPrincipal(identity); // 创建包含属性的认证票据 var ticket = new AuthenticationTicket(principal, properties, "myauth"); return Task.FromResult(HandleRequestResult.Success(ticket)); }
4. 确认Program.cs的认证配置
当前配置已满足需求,若需要明确指定默认挑战方案(可选),可补充如下:
builder.Services.AddAuthentication(options => { options.DefaultScheme = IdentityConstants.ApplicationScheme; options.DefaultSignInScheme = IdentityConstants.ExternalScheme; options.DefaultChallengeScheme = "myauth"; // 可选,指定默认挑战用自定义方案 }) .AddRemoteScheme<MyAuthOptions, MyAuthHandler>("myauth", "My auth", null) .AddIdentityCookies();
验证流程
- 重新运行应用,点击"Register"进入注册页面
- 点击"My auth"按钮,会跳转到自定义登录页,URL中会包含
state和returnUrl参数 - 点击"Click here to sign in"按钮,表单携带参数提交到
/signin-myauth - 认证成功后会自动跳转到Identity的外部登录回调页面,引导完成本地账号关联(或直接登录,若账号已存在)
内容的提问来源于stack exchange,提问作者Peter Morris
相关产品推荐
相关产品推荐

