在 Web API(.Net 框架)中验证 IdentityServer4 令牌

Validate IdentityServer4 token in Web API (.Net framework)

我想在 Web API(.Net Framework 4.7.1) 中验证从 IdentityServer 生成的令牌。

这是我目前在 Startup.cs 网络 API

中所做的
public void Configuration(IAppBuilder app)
{

    app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = "Cookies"
    });

    app.UseOpenIdConnectAuthentication(
        new OpenIdConnectAuthenticationOptions
        {
            RequireHttpsMetadata = false,
            SignInAsAuthenticationType = "Cookies",
            Authority = "https://localhost:44380/",
            RedirectUri = "http://localhost:4200/auth-callback",
            ClientId = "angular",
            Scope = "api1",
            ResponseType = "code"
        });

}

它抛出 code challenge required 错误。

由于设计限制,我将无法使用 IdentityServer/IdentityServer3.AccessTokenValidation,我应该使用 UseOpenIdConnectAuthentication 来验证令牌。

编辑 我能够在 Web API Core 中使用它。这是我的 Startup.cs Web API Core。但不确定如何在 Web API .Net Framework 中执行此操作。我还尝试使用具有以下配置的 IdentityServer/IdentityServer3.AccessTokenValidation 但它抛出 401 错误

public void Configuration(IAppBuilder app)
{
    app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
    {
        Authority = "https://localhost:44380",
        RequiredScopes = new[] { "api1" }
    });
}

Due to the design constraint, I will not be able to use the IdentityServer/IdentityServer3.AccessTokenValidation and I should use UseOpenIdConnectAuthentication to validate the token.

结论完全错误。 OpenIdConnectAuthentication 用于交互式登录,而不用于不记名令牌验证。您可以改用 IdentityServer3.Contrib.AccessTokenValidation

我已经为您和我自己准备了工作 repo。它针对 4.7.2。一切都是硬编码的,但唯一的配置块在 startup.cs

public void Configuration(IAppBuilder app)
{
    app.UseIdentityServerBearerTokenAuthentication(new 
    IdentityServerBearerTokenAuthenticationOptions
    {
        Authority = "https://demo.identityserver.io/",
        RequiredScopes = new[] { "api" }
    });
}

如您所见,我使用了 public Identityserver 实例。

我用了curl 获取令牌:

curl -d "grant_type=client_credentials&client_id=client&client_secret=secret" https://demo.identityserver.io//connect/token

然后打电话给我的 API:

curl -v  -H "Accept: application/json" -H "Authorization: Bearer <The token is here>"  http://localhost/MVCBearerNuget/api/TestApi

答案是:

< HTTP/1.1 200 OK
< Cache-Control: no-cache
< Pragma: no-cache
< Content-Type: application/json; charset=utf-8
< Expires: -1
< Server: Microsoft-IIS/10.0
< X-AspNet-Version: 4.0.30319
< X-Powered-By: ASP.NET
< Date: Tue, 10 Sep 2019 17:37:08 GMT
< Content-Length: 19
<
["value1","value2"]* Connection #0 to host localhost left intact

另一种方法是自己构建中间件,但我的目标是最新的、易于使用并且绝对有效。

我使用 .NET Framework 4.6.1 创建 Web API,对于身份提供者,我使用的是 Identity Server 4(之前我使用的是 Identity Server 3)。最初我确实遇到了问题,但我想出了这个对我来说非常有效的解决方法。请注意,我正在使用 ClientCredentials grantflow。

我正在使用相同的 IdentityServer3.AccessTokenValidation 库进行令牌验证。诀窍是针对内省终点。以下是我的有效配置。

这是 Web 的配置 API,请注意设置 ValidationMode 属性 是至关重要的。

app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
        {
            Authority = ConfigurationManager.AppSettings["AuthServerURI"],
            RequiredScopes = new[] { "comp-read", "stats-read" },
            ClientId = "apiname",
            ClientSecret = "apisecret",
            ValidationMode = ValidationMode.ValidationEndpoint,
            EnableValidationResultCache = true
        });

这就是 API资源和客户端在我的 IDP 中的配置方式。

new ApiResource
            {
                Name = "apiname",
                DisplayName = "Web API",
                Description = "Access to Web API Services",
                ApiSecrets = new List<Secret> {new Secret("apisecret".Sha256())},
                Scopes = new List<Scope> {
                    new Scope("comp-read", "Read access to Comp Db API"),
                    new Scope("stats-read", "Read access to Stats API")
                }

这是其中一个客户端的配置方式。

new Client
            {
                ClientName = "name of the client",
                ClientId = "clientname",
                Enabled = true,
                AllowedGrantTypes = GrantTypes.ClientCredentials,
                ClientSecrets = new List<Secret> {
                    new Secret("secretforclient".Sha256())
                },
                AllowedScopes = new List<string>
                {
                    "stats-read"
                },
                AccessTokenLifetime = 1000
            }

希望这对您有所帮助。谢谢