我的团队和我创建了一个定制的OAuth,用于外部SSO。它可以在本地主机上工作,但是一旦我们将它放到我们的暂存环境中,我们就会得到一个“oauth状态丢失或无效”。错误。
我们使用"https://auth0.com/“进行测试。
为了尝试解决这个问题,我们重写了以下内置的方法,并且通过断点可以看到查询状态返回null。
protected override string BuildChallengeUrl(AuthenticationProperties properties, string redirectUri);
protected override async Task<HandleRequestResult> HandleRemoteAuthenticateAsync();
我需要一些帮助,弄清楚为什么这是一个问题,在舞台上,而不是在本地,因为我们有点困惑。我们的一个理论是,在这些方法中使用的解码器在var properties = Options.StateDataFormat.Unprotect(state);
上会发生变化,因此因为它们不是相同的,所以它们不能相互解码状态。我将把我们的实现放在下面,如果需要的话,我也可以粘贴内置的方法,但我无法理解内置函数的问题所在。
启动:
foreach (var customAuthItem in customAuthList)
{
services.AddAuthentication().AddCustom(customAuthItem.CampaignId, options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.AuthorizationEndpoint = customAuthItem.AuthEndpoint;
options.TokenEndpoint = customAuthItem.TokenEndpoint;
options.UserInformationEndpoint = customAuthItem.UserInfoEndpoint;
options.ClientId = customAuthItem.ClientId;
options.ClientSecret = customAuthItem.ClientSecret;
});
}
选项:
public class CustomAuthenticationOptions : OAuthOptions
{
/// <summary>
/// Initializes a new instance of the <see cref="CustomAuthenticationOptions"/> class.
/// </summary>
public CustomAuthenticationOptions()
{
ClaimsIssuer = CustomAuthenticationDefaults.Issuer;
CallbackPath = CustomAuthenticationDefaults.CallbackPath;
AuthorizationEndpoint = CustomAuthenticationDefaults.AuthorizationEndpoint;
TokenEndpoint = CustomAuthenticationDefaults.TokenEndpoint;
UserInformationEndpoint = CustomAuthenticationDefaults.UserInformationEndpoint;
Scope.Add("openid");
Scope.Add("profile");
Scope.Add("email");
ClaimActions.MapJsonKey(ClaimTypes.Email, "email");
ClaimActions.MapJsonKey(ClaimTypes.Name, "name");
ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub");
}
/// Gets the list of fields to retrieve from the user information endpoint.
/// </summary>
public ISet<string> Fields { get; } = new HashSet<string>
{
"email",
"name",
"sub"
};
缺省值:
public static class CustomAuthenticationDefaults
{
/// <summary>
/// Default value for <see cref="AuthenticationScheme.Name"/>.
/// </summary>
public const string AuthenticationScheme = "Custom";
/// <summary>
/// Default value for <see cref="AuthenticationScheme.DisplayName"/>.
/// </summary>
public static readonly string DisplayName = "Custom";
/// <summary>
/// Default value for <see cref="AuthenticationSchemeOptions.ClaimsIssuer"/>.
/// </summary>
public static readonly string Issuer = "Custom";
/// <summary>
/// Default value for <see cref="RemoteAuthenticationOptions.CallbackPath"/>.
/// </summary>
public static readonly string CallbackPath = "/signin-custom";
/// <summary>
/// Default value for <see cref="OAuthOptions.AuthorizationEndpoint"/>.
/// </summary>
public static readonly string AuthorizationEndpoint = "https://dev-egd511ku.us.auth0.com/authorize";
/// <summary>
/// Default value for <see cref="OAuthOptions.TokenEndpoint"/>.
/// </summary>
public static readonly string TokenEndpoint = "https://dev-egd511ku.us.auth0.com/oauth/token";
/// <summary>
/// Default value for <see cref="OAuthOptions.UserInformationEndpoint"/>.
/// </summary>
public static readonly string UserInformationEndpoint = "https://dev-egd511ku.us.auth0.com/userinfo";
}
处理程序:
protected override async Task<AuthenticationTicket> CreateTicketAsync(
[NotNull] ClaimsIdentity identity,
[NotNull] AuthenticationProperties properties,
[NotNull] OAuthTokenResponse tokens)
{
Serilog.Log.Debug("CustomAuthenticationHandler.CreateTicketAsync: STARTED!");
string endpoint = Options.UserInformationEndpoint;
if (Options.Fields.Count > 0)
{
endpoint = QueryHelpers.AddQueryString(endpoint, "fields", string.Join(',', Options.Fields));
}
using var request = new HttpRequestMessage(HttpMethod.Get, endpoint);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokens.AccessToken);
Serilog.Log.Debug("CustomAuthenticationHandler.CreateTicketAsync: ABOUT TO SEND REQUEST!");
using var response = await Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Context.RequestAborted);
if (!response.IsSuccessStatusCode)
{
Serilog.Log.Debug($"CustomAuthenticationHandler.CreateTicketAsync: FAILED REQUEST: {response.ReasonPhrase}");
await Log.UserProfileErrorAsync(Logger, response, Context.RequestAborted);
throw new HttpRequestException("An error occurred while retrieving the user profile from Custom.");
}
var payloadString = await response.Content.ReadAsStringAsync();
Serilog.Log.Debug($"CustomAuthenticationHandler.CreateTicketAsync: PAYLOAD: {payloadString}");
using var payload = JsonDocument.Parse(payloadString);// Context.RequestAborted));
var principal = new ClaimsPrincipal(identity);
var context = new OAuthCreatingTicketContext(principal, properties, Context, Scheme, Options, Backchannel, tokens, payload.RootElement);
context.RunClaimActions();
await Events.CreatingTicket(context);
return new AuthenticationTicket(context.Principal!, context.Properties, Scheme.Name);
}
编辑:该错误是在成功登录和被重定向回到我们的网站后收到的。我可以通过哨兵面包屑看到状态是正确的,所以这似乎是一个解密问题。
发布于 2022-05-12 13:52:01
事实证明,问题是因为我AddAuthentication()
两次,它忽略了auth方法的后续注册,导致只有一个OAuth工作。这有点问题,因为我们希望为客户端支持多个SSO选项,但可能需要找到一种不同的方法。我很高兴我终于知道问题出在哪里了。
https://stackoverflow.com/questions/72183314
复制相似问题