【问题标题】:Identity Server 4 and ASP.NET Web Forms Client - invalid grant typeIdentity Server 4 和 ASP.NET Web 窗体客户端 - 无效的授权类型
【发布时间】:2021-04-21 20:32:58
【问题描述】:

我已经在本地设置了 Identity Server 4 并添加了一个 MVC Net Core 客户端,没有任何问题。

但我的 .Net Framework Web Forms 应用程序无法正常工作。

当我尝试点击关于(安全页面).aspx 页面时,我收到以下错误:

“抱歉,出现错误:未授权客户端
客户端的授权类型无效”

我已经尝试了所有不同的 Granttype,但都没有成功。

我觉得我在 ID4 中的客户端设置不正确。各种博客文章说我应该使用代码授权,但其他人说使用 id_token。

我在 ID4 服务器应用中设置了如下客户端:

new Client
{
    ClientId = "aspx",
    ClientSecrets = { new Secret("secret".Sha256()) },

    AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,                

    //My web forms aspx client
    RedirectUris = { "http://localhost:5969/" },

    //My web forms aspx client
    PostLogoutRedirectUris = { "http://localhost:5969/" },

    AllowOfflineAccess = true,
    AllowAccessTokensViaBrowser = true,

    RequirePkce = false,

    AllowedScopes =
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile                    
    },
}

我的 Web 表单应用程序中的 Startup.cs(我正在使用来自 https://github.com/IdentityServer/IdentityServer3.Samples/blob/master/source/Clients/WebFormsClient/Startup.cs 的 \WebFormsClient\ 示例)

我对 https://localhost:5001/connect/userinfo 应该是什么感到有些困惑 - 我得到了 401。

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions()
        {
            AuthenticationType = "Cookies",
            ExpireTimeSpan = TimeSpan.FromMinutes(10),
            SlidingExpiration = true
        });

        JwtSecurityTokenHandler.InboundClaimTypeMap.Clear();
      
        app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
        {                
            AuthenticationType = "oidc",
            SignInAsAuthenticationType = "Cookies",                
            Authority = "https://localhost:5001/",
            ClientId = "aspx",
            RedirectUri = "http://localhost:5969/",
            PostLogoutRedirectUri = "http://localhost:5969/",
            ResponseType = "id_token token",
            Scope = "openid profile email",
            UseTokenLifetime = false,
            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                SecurityTokenValidated = async n =>
                {
                    var claims_to_exclude = new[]
                    {
                        "aud", "iss", "nbf", "exp", "nonce", "iat", "at_hash"
                    };

                    var claims_to_keep =
                        n.AuthenticationTicket.Identity.Claims
                        .Where(x => false == claims_to_exclude.Contains(x.Type)).ToList();
                    claims_to_keep.Add(new Claim("id_token", n.ProtocolMessage.IdToken));

                    if (n.ProtocolMessage.AccessToken != null)
                    {
                        claims_to_keep.Add(new Claim("access_token", n.ProtocolMessage.AccessToken));

                        var userInfoClient = new UserInfoClient(new Uri("https://localhost:5001/connect/userinfo"), n.ProtocolMessage.AccessToken);
                        var userInfoResponse = await userInfoClient.GetAsync();
                        var userInfoClaims = userInfoResponse.Claims
                            .Where(x => x.Item1 != "sub") // filter sub since we're already getting it from id_token
                            .Select(x => new Claim(x.Item1, x.Item2));
                        claims_to_keep.AddRange(userInfoClaims);
                    }

                    var ci = new ClaimsIdentity(
                        n.AuthenticationTicket.Identity.AuthenticationType,
                        "name", "role");
                    ci.AddClaims(claims_to_keep);

                    n.AuthenticationTicket = new Microsoft.Owin.Security.AuthenticationTicket(
                        ci, n.AuthenticationTicket.Properties
                    );
                },
                RedirectToIdentityProvider = n =>
                {
                    if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
                    {
                        var id_token = n.OwinContext.Authentication.User.FindFirst("id_token")?.Value;
                        n.ProtocolMessage.IdTokenHint = id_token;
                    }

                    return Task.FromResult(0);
                }
            }
        });
        app.UseStageMarker(PipelineStage.Authenticate);
    }
}

【问题讨论】:

  • "id_token token" 是隐式流,因此您需要将其包含在 AllowedGrantTypes 中。
  • 打开并观察身份服务器上的跟踪级别日志记录也很有用;它详细说明了问题所在。
  • 优秀 - 工作!我设置 AllowedGrantTypes = GrantTypes.Implicit 并从网络表单范围中删除“电子邮件”
  • 太好了 - 我会添加一个答案;随意接受它。

标签: c# webforms identityserver4


【解决方案1】:

“id_token token”是Implicit flow,所以你需要把它包含在你的AllowedGrantTypes中。

关于UserInfoendpoint,它只是根据您调用它的访问令牌返回有关用户的声明。获得 401 响应可能意味着您没有传递有效的访问令牌。如果您需要额外的用户声明并且您只有访问令牌但没有 ID 令牌,它会很有用。

【讨论】:

    猜你喜欢
    • 2019-11-25
    • 2020-01-11
    • 2020-08-06
    • 1970-01-01
    • 1970-01-01
    • 2018-11-02
    • 1970-01-01
    • 2021-03-06
    • 2021-08-07
    相关资源
    最近更新 更多