Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/azure/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用C语言验证PS256编码的JWT#_C#_.net_Jwt_Rsa_Jose - Fatal编程技术网

C# 使用C语言验证PS256编码的JWT#

C# 使用C语言验证PS256编码的JWT#,c#,.net,jwt,rsa,jose,C#,.net,Jwt,Rsa,Jose,我的任务是验证一个使用PS256算法编码的JWT令牌,在过去的两天里,我遇到了麻烦。我缺乏这方面的知识,我一直在慢慢地解决这个问题,尝试不同的解决方案 // Encoded eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZDEyMzQifQ.eyJpc3MiOiJmb28uYmFyLnRlc3Rpc3N1ZXIiLCJleHAiOjE1NTEyMDEwNjgsImF0X2hhc2giOiJqaFl3c1pyTnZ0dFNYQnR6QVMtWlNn

我的任务是验证一个使用PS256算法编码的JWT令牌,在过去的两天里,我遇到了麻烦。我缺乏这方面的知识,我一直在慢慢地解决这个问题,尝试不同的解决方案

// Encoded
eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZDEyMzQifQ.eyJpc3MiOiJmb28uYmFyLnRlc3Rpc3N1ZXIiLCJleHAiOjE1NTEyMDEwNjgsImF0X2hhc2giOiJqaFl3c1pyTnZ0dFNYQnR6QVMtWlNnIn0.yJePyxdJWyydG4HM97oQag6ulGKa5Afw-LHYYEXz7lVy8v0IJD0mSO9WtowlWJIeD2Vvthuj71XUfHsgz0LD9rK0VBucJbd_OiIXpbwPUqBcdj82DNLFXDJfCJnUC-Rv8QP7OUVBvLjvBQ6WYMrx1Qnq8xP6qeL_ohKwRmo6EDhZRkYBz9gFhfha1ZlKcnyR73nXdShwy7OmmyiRvVWPBf_GgSsfz8FNNoKySW1MA4tRa7cl3zPlyCnWyLaZ3kcQsmTqarHG--YXSDF5ozZ_Sx6TkunCxrOYzOFNcPyeIWqI84cemM6TgMBw9jhzMCk7Y4Fzxe5KEYJH4GlGA4s4zg

// Header
{
    "alg": "PS256",
    "typ": "JWT",
    "kid": "kid1234"
}

// Payload
{
    "iss": "foo.bar.testissuer",
    "exp": 1551201068,
    "at_hash": "jhYwsZrNvttSXBtzAS-ZSg"
}
我有一个RS256编码JWT的工作实现,它使用Microsoft.IdentityModel.Tokens和System.IdentityModel.Tokens.JWT中提供的JWTSecurityTokenHandler。对于RS256实现,我有一个IssuerSigningKeyResolver,它为孩子进行自定义检查并提供公钥

var tokenValidationParameters = new TokenValidationParameters
{
    ValidIssuer = issuer,
    ValidateLifetime = true,
    RequireSignedTokens = true,
    RequireExpirationTime = true,
    ValidateAudience = false,
    ValidateIssuer = true,
    IssuerSigningKeyResolver = (string token, SecurityToken securityToken, string kid, TokenValidationParameters validationParameters) =>
    {
        // Custom kid checks

        var rsa = RSA.Create();
        rsa.ImportParameters(new RSAParameters
        {
            Exponent = Base64UrlEncoder.DecodeBytes(matchingKid.E),
            Modulus = Base64UrlEncoder.DecodeBytes(matchingKid.N),
        });
        latestSecurityKeys.Add(matchingKid.Kid, new RsaSecurityKey(rsa));

        var securityKeys = new SecurityKey[1]
        {
            new RsaSecurityKey(rsa)
        };

        return securityKeys;
    }
};

var tokenHandler = new JwtSecurityTokenHandler();
try
{
    var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out SecurityToken validatedToken);
    return true;
}
catch (SecurityTokenException ex)
{
    // Do something with ex
    return false;
}
此实现不适用于PS256编码的JWT。我在System.IdentityModel.Tokens.Jwt内部调试了,但似乎即使PS256在支持的算法列表中,验证也失败了


我必须再次声明,我在这个问题上的知识是有限的。据我所知,RSA256和PS256属于同一个算法家族?我是否最好使用另一个库(如jose JWT)创建PS256 JWT的自定义验证?

在向Microsoft提出问题后,现在似乎Microsoft.IdentityModel.Tokens不支持此类验证System.IdentityModel.Tokens.Jwt。详情可在此找到-

最后,我使用jose jwt和一些自定义检查验证了我的令牌

private bool IsValid(string token, string issuer, string configId)
{
    var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
    var jwtSecurityToken = jwtSecurityTokenHandler.ReadToken(token) as JwtSecurityToken;

    // Extract the kid from token header
    var kidHeader = jwtSecurityToken.Header.Where(k => k.Key.ToLower() == "kid")?.FirstOrDefault();
    if (kidHeader?.Value == null) ThrowInvalidOperation($"Failed to find matching kid for Issuer: {issuer.ToLower() }");

    var kid = kidHeader?.Value as string;

    // Extract the expiration time from token payload
    var expirationTime = jwtSecurityToken.Payload?.Exp;
    if (expirationTime == null) ThrowInvalidOperation($"Failed to find matching expiration time for Issuer: {issuer.ToLower() }");

    // Decode to verify signature
    var verifiedToken = JWT.Decode(token, GetPublicKey(kid, issuer, providerId));

    if (verifiedToken != null)
    {
        var json = JsonConvert.DeserializeObject<dynamic>(verifiedToken);
        return IsValidIssuer(json, issuer) && IsValidExpirationTime(json, expirationTime);
    }
    else
    {
        return false;
    }

    void ThrowInvalidOperation(string msg) => throw new InvalidOperationException(msg);
}

private bool IsValidIssuer(dynamic json, string issuer)
{
    if (json != null && issuer != null)
    {
        if (json["iss"] == issuer)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    return false;
}

private bool IsValidExpirationTime(dynamic json, int? expTime)
{
    if (json != null && expTime != null)
    {
        if (json["exp"] == expTime)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    return false;
}

private RSA GetPublicKey(string kid, string validIssuer, string configId)
{
    var openIdConfig = openIdConfigurationProvider.GetOpenIdConfiguration(configId);
    var matchingKid = openIdConfig?.JsonWebKeySet?.Keys?.FirstOrDefault(x => x.Kid == kid);
    if (matchingKid == null)
    {
        throw new InvalidOperationException($"kid is null");
    }

    var rsa = RSA.Create();
    rsa.ImportParameters(new RSAParameters
    {
        Exponent = Base64UrlEncoder.DecodeBytes(matchingKid.E),
        Modulus = Base64UrlEncoder.DecodeBytes(matchingKid.N),
    });

    return rsa;
}
private bool有效(字符串令牌、字符串颁发者、字符串配置ID)
{
var jwtSecurityTokenHandler=新的jwtSecurityTokenHandler();
var jwtSecurityToken=jwtSecurityTokenHandler.ReadToken(令牌)作为jwtSecurityToken;
//从令牌头中提取kid
var kidHeader=jwtSecurityToken.Header.Where(k=>k.Key.ToLower()==“kid”)?.FirstOrDefault();
if(kidHeader?.Value==null)ThrowInvalidOperation($”未能找到与颁发者匹配的kid:{Issuer.ToLower()}”);
var kid=kidHeader?值作为字符串;
//从令牌负载中提取过期时间
var expirationTime=jwtSecurityToken.Payload?.Exp;
if(expirationTime==null)ThrowInvalidOperation($”未能找到与颁发者匹配的过期时间:{Issuer.ToLower()}”);
//解码以验证签名
var-verifiedToken=JWT.Decode(令牌、GetPublicKey(kid、发卡机构、providerId));
如果(已验证终止!=null)
{
var json=JsonConvert.DeserializeObject(verifiedToken);
返回isValidisUser(json,发卡机构)和&isValidExirationTime(json,到期时间);
}
其他的
{
返回false;
}
void ThrowInvalidOperation(字符串消息)=>抛出新的InvalidOperationException(消息);
}
私有bool-isvalidisuer(动态json,字符串颁发者)
{
if(json!=null&&issuer!=null)
{
如果(json[“iss”]==发行人)
{
返回true;
}
其他的
{
返回false;
}
}
返回false;
}
私有bool IsValidExpirationTime(动态json,int?expTime)
{
if(json!=null&&expTime!=null)
{
if(json[“exp”]==expTime)
{
返回true;
}
其他的
{
返回false;
}
}
返回false;
}
私有RSA GetPublicKey(字符串kid、字符串ValidisUser、字符串configId)
{
var openIdConfig=openIdConfigurationProvider.GetOpenIdConfiguration(configId);
var matchingKid=openIdConfig?.JsonWebKeySet?.Keys?.FirstOrDefault(x=>x.Kid==Kid);
if(matchingKid==null)
{
抛出新的InvalidOperationException($“kid为null”);
}
var rsa=rsa.Create();
rsa.ImportParameters(新参数)
{
Exponent=Base64UrlEncoder.DecodeBytes(matchingKid.E),
模数=Base64UrlEncoder.DecodeBytes(匹配kid.N),
});
返回rsa;
}

您是否尝试过JWT.io?首先尝试验证一下。显然,该令牌已过期,因此您需要生成一个新的令牌,并将您的公钥和私钥粘贴到相关框中。这也可能有用:我提供的令牌只是一个示例。我可以使用公钥验证jwt.io上的令牌,因此我知道它的编码是正确的。我的问题是如何使用.NET进行相同的验证。您是否使用.NET Framework 4.5+?你在用Owin吗?您可以使用
IdentityServer3.AccessTokenValidation
nuget包调用一个方法来设置它:
UseIdentityServerBealerTokenAuthentication
Ok,我现在明白了。但这很奇怪,因为在JWT网站上,有相当多的库支持PS256算法。是的,这是最让我困惑的开始。事实证明,jose jwt和BouncyCastle是唯一支持一切的公司。谢谢你的帮助和建议。