Owin / Katana UseJwtBearerAuthentication始终返回401

时间:2018-01-23 02:26:04

标签: authentication bearer-token owin-middleware

我需要在.NET 4.6.1 Web API项目以及.NET Core 2.0 Web项目中实现JWT承载身份验证。

我成功地使用Microsoft的sample启动并运行了核心项目。

我跟随Scott Allen的sample了解.NET 4.6.1项目。

我的4.6.1代码如下所示:

public void ConfigureAuth(IAppBuilder app)
    {
        // Application requuires AD Bearer tokens for access
        app.UseJwtBearerAuthentication(
            new JwtBearerAuthenticationOptions
            {
                AuthenticationMode = AuthenticationMode.Active,
                TokenValidationParameters = new TokenValidationParameters
                {
                    ValidIssuer = "https://validissuer.blahblah.com/",
                    ValidAudience = "https://validaudience.blahblah.com"
                }
            });
    }

相同的标记将在.NET Core API中正确验证,但不会在.NET 4.6.1 API中验证,我相信我错过了一些小问题。有什么想法吗?

附带问题:在生产环境中应该验证哪些内容的最佳做法是什么?这两个实例都试图验证发行人和受众,但是我应该考虑验证其他任何内容吗?

-Tim

2 个答案:

答案 0 :(得分:1)

您需要设置IssuerSigningKey属性。如果您不知道如何手动获取密钥,请参考以下示例,根据授权自动对IssuerSigningKey进行转储:

using System.Linq;
using System.Threading;
using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Jwt;
public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var authority = "https://<your-authority>/";
        var keyResolver = new OpenIdConnectSigningKeyResolver(authority);
        app.UseJwtBearerAuthentication(
            new JwtBearerAuthenticationOptions
            {
                AuthenticationMode = AuthenticationMode.Active,
                TokenValidationParameters = new TokenValidationParameters()
                {
                    AuthenticationType = "Bearer",
                    ValidIssuer = "https://<your-authority>/",
                    ValidateAudience = false,
                    ValidateIssuer = true,
                    RequireExpirationTime = true,
                    ValidateLifetime = true,
                    IssuerSigningKeyResolver = (token, securityToken, kid, parameters) => keyResolver.GetSigningKey(kid)
                }
            });
    }

    private class OpenIdConnectSigningKeyResolver
    {
        private readonly OpenIdConnectConfiguration openIdConfig;

        public OpenIdConnectSigningKeyResolver(string authority)
        {
            var cm = new ConfigurationManager<OpenIdConnectConfiguration>($"{authority.TrimEnd('/')}/.well-known/openid-configuration", new OpenIdConnectConfigurationRetriever());
            openIdConfig = AsyncHelper.RunSync(async () => await cm.GetConfigurationAsync());
        }

        public SecurityKey[] GetSigningKey(string kid)
        {
            // Find the security token which matches the identifier
            return new[] { openIdConfig.JsonWebKeySet.GetSigningKeys().FirstOrDefault(t => t.KeyId == kid) };
        }
    }

    private static class AsyncHelper
    {
        private static readonly TaskFactory TaskFactory = new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);

        public static void RunSync(Func<Task> func)
        {
            TaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult();
        }

        public static TResult RunSync<TResult>(Func<Task<TResult>> func)
        {
            return TaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult();
        }
    }
}

答案 1 :(得分:0)

由于您已将TokenValidationParameters的新实例分配给相应的媒体资源,我认为您还应该提供有效的IssuerSigningKey

    builder.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
        {
            AuthenticationMode           = AuthenticationMode.Active,
            TokenValidationParameters    = new TokenValidationParameters
            {
                AuthenticationType = "Bearer",
                ValidIssuer = "https://validissuer.blahblah.com/",
                ValidAudience = "https://validaudience.blahblah.com",
                IssuerSigningKey   = new InMemorySymmetricSecurityKey(Encoding.UTF8.GetBytes("MySecret")),
            }
        });