"Message": "Authorization has been denied for this request." OWIN 中间件

"Message": "Authorization has been denied for this request." OWIN middleware

我将基于令牌的身份验证添加到我的 OWIN 中间件并且可以生成令牌。但是在使用时,使用 Authorize 属性的 API 调用的令牌我总是得到 "Authorization has been denied for this request." 尽管没有 Authorize 属性但它工作正常。这是我的 startup.cs 和控制器方法。有什么想法,有什么问题吗?

startup.cs

    public void Configuration(IAppBuilder app)
            {
                var issuer = ConfigurationManager.AppSettings["issuer"];
                var secret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["secret"]);
                app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
                {
                    AuthenticationType = DefaultAuthenticationTypes.ExternalBearer,
                    AllowInsecureHttp = true,
                    TokenEndpointPath = new PathString("/token"),
                    AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
                    Provider = new SimpleAuthProvider(),
                    AccessTokenFormat = new JwtFormat(issuer)
                });
                app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
                {
                    AuthenticationType = DefaultAuthenticationTypes.ExternalBearer,
                    AuthenticationMode = AuthenticationMode.Active,
                    AllowedAudiences = new[] { "*" },
                    IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
                    {
                        new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
                    }
                });
                container = BuildDI();
                var config = new HttpConfiguration();
                config.Formatters.XmlFormatter.UseXmlSerializer = true;
                config.MapHttpAttributeRoutes();
                config.SuppressDefaultHostAuthentication();
                config.Filters.Add(new HostAuthenticationFilter(DefaultAuthenticationTypes.ExternalBearer));
                config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
                app.UseCors(CorsOptions.AllowAll);
                app.UseSerilogRequestContext("RequestId");
                app.UseAutofacMiddleware(container);
                app.UseAutofacWebApi(config);
                app.UseWebApi(config);
                RegisterShutdownCallback(app, container);
            }

 public class SimpleAuthProvider: OAuthAuthorizationServerProvider
        {
            public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
            {

                if (context.UserName != context.Password)
                {
                    context.SetError("invalid_grant", "The user name or password is incorrect");
                    context.Rejected();
                    return Task.FromResult<object>(null);
                }

                var ticket = new AuthenticationTicket(SetClaimsIdentity(context), new AuthenticationProperties());
                context.Validated(ticket);

                return Task.FromResult<object>(null);
            }

            public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
            {
                context.Validated();
                return Task.FromResult<object>(null);
            }

            private static ClaimsIdentity SetClaimsIdentity(OAuthGrantResourceOwnerCredentialsContext context)
            {
                var identity = new ClaimsIdentity(DefaultAuthenticationTypes.ExternalBearer);
                identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
                return identity;
            }
        }

API 控制器方法:

 [HttpGet]
        [Route("sampleroute")]
        [Authorize]
        public async Task<HttpResponseMessage> GetSamples(string search)
        {
            try
            {

                HttpResponseMessage response;
                using (HttpClient client = new HttpClient(Common.CreateHttpClientHandler()))
                {
                     response = await client.GetAsync("test url");
                }
                var result = response.Content.ReadAsStringAsync().Result;
                Samples[] sampleArray = JsonConvert.DeserializeObject<Samples[]>(result);
                var filteredSamples = sampleArray .ToList().Where(y => y.NY_SampleName.ToUpper().Contains(search.ToUpper())).Select(n=>n);
                log.Information("<==========Ended==========>");
                return  Request.CreateResponse(HttpStatusCode.OK,filteredSamples);

            }
            catch (Exception ex)
            {
                log.Error($"Error occured while pulling the Samples:  {ex.ToString()}");
                return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.ToString());
            }
        }

据我了解,您需要添加 header: Authorization: Bearer "token"。 如果您尚未修改授权请求的默认实现,则步骤如下:

  1. 在端点注册用户:

    /api/Account/Register
    
  2. Post 到 /token 以下项目:
    • grant_type: 密码
    • 用户名:"the username you registered"
    • 密码:"the password you registered for the user"
  3. 您将在响应中收到一个令牌
  4. 复制该令牌并创建一个对您使用类型为 [Authorize] 的过滤器保护的方法的请求:

     Authorization: Bearer "the_token_you_copied_earlier"
    

    不用说,如果您使用 Postman 或 Fiddler 来发出和接收请求,这对您来说可能会非常容易,因为它向您展示了一切是如何工作的。

可能是允许的观众有问题。 这里

 app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
 {
     ...     
     AllowedAudiences = new[] { "*" },
     ...
 }

您设置了允许的观众。令牌 aud 声明将根据 AllowedAudiences 的列表进行检查。但是您永远不会向令牌添加任何受众。

在我们的项目中,我使用了基于 http://bitoftech.net/2014/10/27/json-web-token-asp-net-web-api-2-jwt-owin-authorization-server/

中显示的代码的 CustomJwtFormat

将通过调用

生成令牌
var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey);

第二个参数负责JWT中的aud声明:

来自 https://msdn.microsoft.com/en-us/library/dn451037(v=vs.114).aspx :

audience Type: System.String

If this value is not null, a { aud, 'audience' } claim will be added.

在令牌授权中设置 aud 声明后应该可以正常工作。