JWT令牌授权不起作用。

9

我将尝试创建Jwt令牌授权。为此,我有一个包含以下代码的发行者部分:

public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
    context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] {"*"});
    Users user;
    using (var db = new UserStore())
    {
        user = Task.Run(()=> db.FindUser(context.UserName, context.Password, context.ClientId)).Result;
    }
    if (user == null)
    {
        context.SetError("invalid_grant", "The user name or password is incorrect");
        return Task.FromResult<object>(null);
    }
    var identity = new ClaimsIdentity("JWT");
    identity.AddClaim(new Claim(ClaimTypes.Name, user.Email));
    identity.AddClaim(new Claim("sub", context.UserName));
    identity.AddClaim(new Claim(ClaimTypes.Role, user.Roles.Name));

    var props = new AuthenticationProperties(new Dictionary<string, string>
    {
        {
            "audience", context.ClientId ?? string.Empty
        }
    });
    var ticket = new AuthenticationTicket(identity, props);
    context.Validated(ticket);
    return Task.FromResult<object>(null);
}

还有一个“资源”部分,应该接受令牌:

public void ConfigureOAuth(IAppBuilder app)
{
    var issuer = SiteGlobal.Issuer;
    var audience = SiteGlobal.Audience;
    var secret = TextEncodings.Base64Url.Decode(SiteGlobal.Secret);
    app.UseJwtBearerAuthentication(
    new JwtBearerAuthenticationOptions
    {
        AuthenticationMode = AuthenticationMode.Active,
        AllowedAudiences = new[] { audience },
        IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
        {
            new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
        }
    });
}

据我所见,发行的令牌是有效的(我在jwt.io上进行了验证),因此问题出在别处。当我在Postman中发送带有[Authorize]属性保护的控制器调用时,它总是返回401代码。请问如何解决这个问题?
附注:这是我实现自定义Jwt格式的方式:
public string Protect(AuthenticationTicket data)
{
    if (data == null)
    {
        throw new ArgumentNullException("data");
    }
    string audienceId = data.Properties.Dictionary.ContainsKey(AudiencePropertyKey) ? data.Properties.Dictionary[AudiencePropertyKey] : null;
    if (string.IsNullOrWhiteSpace(audienceId)) throw new InvalidOperationException("AuthenticationTicket.Properties does not include audience");
    Audience audience;
    using (var store = new AudienceStore())
    {
        audience = Task.Run(()=> store.FindAudience(audienceId)).Result;
    }
    var symmetricKeyAsBase64 = audience.Base64Secret;
    var signingKey = new InMemorySymmetricSecurityKey(Encoding.UTF8.GetBytes(symmetricKeyAsBase64));
    var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256Signature, SecurityAlgorithms.Sha256Digest);
    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, signingCredentials);
    var handler = new JwtSecurityTokenHandler();
    var jwt = handler.WriteToken(token);
    return jwt;
}

PS:很抱歉,但我忘记解释了“issuer”代码的部分,它是独立的应用程序,而“audience”是受保护的Web API。这是两个不同的应用程序独立运行。


这个 http://security.stackexchange.com/a/128882/131820 对你有帮助吗? - Tatranskymedved
我不确定这个。头文件有问题吗?我会收到类似于错误请求而不是未经授权的东西。 - andrey.shedko
我对jwt没有经验,只有通过URL进行REST查询的经验,其中需要请求头Authorization: Basic <加密的用户名:密码>,如果出现任何错误(密码/名称/语法),它会向我抛出401。 - Tatranskymedved
1
@Tatranskymedved 那是用于基本身份验证的,而不是JWT。JWT需要一个 Authorization: Bearer <jwt> 格式。 - cchamberlain
请确保 'SiteGlobal.Issuer' 和 '_issuer' 具有相同的值(区分大小写)。 - Jek
1
当我安装JWT并且一直遇到401错误时,我也碰到了类似的问题。尝试更改启动类中的顺序,以使ConfigureOAuth在任何其他操作之前完成。这对我有用。(Asp.Net Core WebAPI)。 - Stephen McDowell
2个回答

4
在Postman中,确保您按照以下格式发送授权标头:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

Postman授权标头

确保您将授权选项卡设置为Type: No Auth

如果问题仍然存在,请在GrantResourceOwnerCredentials中设置断点,并查看是否到达该点。如果您想要更早地调试事件链,请考虑重写OAuthAuthorizationServerProviderValidateClientAuthentication方法,该方法应该在GrantResourceOwnerCredentials之前被调用。


这是来自Postman的代码:Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1bmlxdWVfbmFtZSI6ImFuZHJleS5zaGVka29AZ21haWwuY29tIiwic3ViIjoiYW5kcmV5LnNoZWRrb0BnbWFpbC5jb20iLCJyb2xlIjoiQWRtaW4iLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjUyNzk5IiwiYXVkIjoiMDk5MTUzYzI2MjUxNDliYzhlY2IzZTg1ZTAzZjAwMjIiLCJleHAiOjE0ODc3NzIxOTEsIm5iZiI6MTQ4Nzc3MDM5MX0.5GFpvU08CjaS5LTH0vRVFIGuilenkEgVu_aJLma4lPo - andrey.shedko
这是个问题 - 在“资源”API中我没有安装Asp.Net Identity,正如本教程中所说-http://bitoftech.net/2014/10/27/json-web-token-asp-net-web-api-2-jwt-owin-authorization-server/comment-page-3/#comment-97300。授权资源所有者凭据方法只有在“发行人”部分出现。 - andrey.shedko
@andrey.shedko,你没有发布你在Postman中尝试运行的内容,但是401错误提示有些授权未能通过。设置断点可以让你检查和找到具体的失败点。如果你移除Authorized属性并在Postman中运行请求,它是否能够正常工作? - cchamberlain

2
我刚试过了ASP.NET Web API 2中使用Owin实现JSON Web Token中提到的演示项目,一切都按预期正常运行。
我注意到你对Protect方法的实现与文章中给出的样例有很大的不同。我建议你先比较一下你的实现和文章中的例子,并尝试让它正常工作。
另外,请确保发行者、受众和密钥在两个服务器上是相同的。
如果您提供完整的源代码,我可以继续进行调查。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接