首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >自定义“oauth状态丢失或无效”

自定义“oauth状态丢失或无效”
EN

Stack Overflow用户
提问于 2022-05-10 08:54:16
回答 1查看 107关注 0票数 1

我的团队和我创建了一个定制的OAuth,用于外部SSO。它可以在本地主机上工作,但是一旦我们将它放到我们的暂存环境中,我们就会得到一个“oauth状态丢失或无效”。错误。

我们使用"https://auth0.com/“进行测试。

为了尝试解决这个问题,我们重写了以下内置的方法,并且通过断点可以看到查询状态返回null。

代码语言:javascript
运行
复制
protected override string BuildChallengeUrl(AuthenticationProperties properties, string redirectUri);
protected override async Task<HandleRequestResult> HandleRemoteAuthenticateAsync();

我需要一些帮助,弄清楚为什么这是一个问题,在舞台上,而不是在本地,因为我们有点困惑。我们的一个理论是,在这些方法中使用的解码器在var properties = Options.StateDataFormat.Unprotect(state);上会发生变化,因此因为它们不是相同的,所以它们不能相互解码状态。我将把我们的实现放在下面,如果需要的话,我也可以粘贴内置的方法,但我无法理解内置函数的问题所在。

启动:

代码语言:javascript
运行
复制
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;
                    });
                }

选项:

代码语言:javascript
运行
复制
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"
    };

缺省值:

代码语言:javascript
运行
复制
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";
}

处理程序:

代码语言:javascript
运行
复制
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);
    }

编辑:该错误是在成功登录和被重定向回到我们的网站后收到的。我可以通过哨兵面包屑看到状态是正确的,所以这似乎是一个解密问题。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-05-12 13:52:01

事实证明,问题是因为我AddAuthentication()两次,它忽略了auth方法的后续注册,导致只有一个OAuth工作。这有点问题,因为我们希望为客户端支持多个SSO选项,但可能需要找到一种不同的方法。我很高兴我终于知道问题出在哪里了。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72183314

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档