为什么[Authorize]属性返回401状态码JWT + Asp.net Web Api?

时间:2018-01-02 11:11:26

标签: asp.net-web-api2 jwt owin

我很难找到使用asp.net web api进行JWT令牌认证的问题。这是我第一次与JWT& amp; Web Api身份验证&授权。

我已经实现了以下代码。

Startup.cs

public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888
            ConfigureOAuthTokenGeneration(app);
            ConfigureOAuthTokenConsumption(app);
        }
        private void ConfigureOAuthTokenGeneration(IAppBuilder app)
        {

            OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
            {
                //For Dev enviroment only (on production should be AllowInsecureHttp = false)
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/oauth/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
                Provider = new OAuthTokenProvider(),
                RefreshTokenProvider = new RefreshTokenProvider(),
                AccessTokenFormat = new Provider.JwtFormat("http://localhost:49860")
            };

            // OAuth 2.0 Bearer Access Token Generation
            app.UseOAuthAuthorizationServer(OAuthServerOptions);

        }
        private void ConfigureOAuthTokenConsumption(IAppBuilder app)
        {
            var issuer = "http://localhost:49860";
            string audienceId = Config.AudienceId;
            byte[] audienceSecret = TextEncodings.Base64Url.Decode(Config.AudienceSecret);

            // Api controllers with an [Authorize] attribute will be validated with JWT
            app.UseJwtBearerAuthentication(
                new JwtBearerAuthenticationOptions
                {
                    AuthenticationMode = AuthenticationMode.Active,
                    AllowedAudiences = new[] { audienceId },
                    IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
                    {
                        new SymmetricKeyIssuerSecurityTokenProvider(issuer, audienceSecret)
                    }
                });
        }

    }   

OAuthTokenProvider.cs

public class OAuthTokenProvider : OAuthAuthorizationServerProvider
{
    public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        // validate client credentials (demo)
        // should be stored securely (salted, hashed, iterated)
        context.Validated();
        return Task.FromResult<object>(null);
    }

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        var allowedOrigin = "*";
        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
        /***Note: Add User validation business logic here**/            
        if (context.UserName != context.Password)
        {
            context.SetError("invalid_grant", "The user name or password is incorrect.");
            return;
        }
        var props = new AuthenticationProperties(new Dictionary<string, string>
        {
            { "as:client_id", "Kaushik Thanki" }
        });
        ClaimsIdentity oAuthIdentity = new ClaimsIdentity("JWT");
        var ticket = new AuthenticationTicket(oAuthIdentity, props);
        context.Validated(ticket);
    }
}

JwtFormat.cs

 public class JwtFormat : ISecureDataFormat<AuthenticationTicket>
    {
        private readonly string _issuer = string.Empty;
        public JwtFormat(string issuer)
        {
            _issuer = issuer;
        }
        public string Protect(AuthenticationTicket data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            string audienceId = Config.AudienceId;
            string symmetricKeyAsBase64 = Config.AudienceSecret;
            var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
            var issued = data.Properties.IssuedUtc;
            var expires = data.Properties.ExpiresUtc;

            var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime);
            var handler = new JwtSecurityTokenHandler();
            var jwt = handler.WriteToken(token);
            return jwt;

        }

        public AuthenticationTicket Unprotect(string protectedText)
        {
            throw new NotImplementedException();
        }
    }

RefreshTokenProvider.cs

public class RefreshTokenProvider : IAuthenticationTokenProvider
    {
        private static ConcurrentDictionary<string, AuthenticationTicket> _refreshTokens = new ConcurrentDictionary<string, AuthenticationTicket>();

        public void Create(AuthenticationTokenCreateContext context)
        {
            throw new NotImplementedException();
        }

        public async Task CreateAsync(AuthenticationTokenCreateContext context)
        {
            var guid = Guid.NewGuid().ToString();

            // maybe only create a handle the first time, then re-use for same client
            // copy properties and set the desired lifetime of refresh token
            var refreshTokenProperties = new AuthenticationProperties(context.Ticket.Properties.Dictionary)
            {
                IssuedUtc = context.Ticket.Properties.IssuedUtc,
                ExpiresUtc = DateTime.UtcNow.AddYears(1)
            };
            var refreshTokenTicket = new AuthenticationTicket(context.Ticket.Identity, refreshTokenProperties);

            //_refreshTokens.TryAdd(guid, context.Ticket);
            _refreshTokens.TryAdd(guid, refreshTokenTicket);

            // consider storing only the hash of the handle
            context.SetToken(guid);
        }

        public void Receive(AuthenticationTokenReceiveContext context)
        {
            throw new NotImplementedException();
        }

        public async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
        {
            AuthenticationTicket ticket;
            if (_refreshTokens.TryRemove(context.Token, out ticket))
            {
                context.SetTicket(ticket);
            }
        }
    }

现在,一旦我通过身份验证(我保持虚拟的初始级别匹配相同的用户名和密码)&amp;得到了令牌&amp;刷新令牌。 当我请求使用[Authorize]属性修饰的方法时,我总是获得401状态代码。

我按照邮递员的方式测试这种方法

enter image description here

任何帮助或指导都将非常感激。我花了两天时间为这个找到了解决办法,但一切都是徒劳的。

0 个答案:

没有答案