URL编码

时间:2018-03-08 17:22:09

标签: c# jwt sha256

我已经搜索了每个角落和裂缝,以解决我的问题,但我似乎无法找到一个。

我有一个使用方法来创建JSON Web令牌的类。我创建的网络令牌需要与以下内容相匹配(注意我的秘密最右边没有数字1):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBrZXkiOiIxMjMtNDU2LTc4OS0wIiwicmVzb3VyY2UiOiJnZXRfZ2VvY29kZSJ9.xGLb92d6yVLqLf5TnrahMCxm-OGTHmXiXLvnRUqLWYM

我生成的令牌与上面的令牌匹配,除了在令牌的最右端随机附加数字1的事实:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBrZXkiOiIxMjMtNDU2LTc4OS0wIiwicmVzb3VyY2UiOiJnZXRfZ2VvY29kZSJ9.xGLb92d6yVLqLf5TnrahMCxm-OGTHmXiXLvnRUqLWYM1

正如你所看到的,这就是JWT的秘密部分。让我演示如何生成和加密令牌,以便您可以帮助诊断问题。我将向您展示整个课程,然后引导您完成这些方法。

以下是整个班级:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Security.Cryptography;

namespace Project.JWT
{
    public class Token
    {

        public string CreateToken(string resource, string appkey, string secret, string algorithm)
        {
            if (algorithm != "HS256")
                return "Algorithm not supported";

            JwtPayload payload = new JwtPayload
            {
                appkey = appkey,
                resource = resource
            };

            return EncodeToken(payload, secret);

        }

        public static string EncodeToken(JwtPayload jwtPayload, string secret)
        {
            const string algorithm = "HS256";

            var header = new Header
            {
                typ = "JWT",
                alg = algorithm
            };

            var jwt = Base64Encode(JsonConvert.SerializeObject(header)) + "." + Base64Encode(JsonConvert.SerializeObject(jwtPayload));

            jwt += "." + Sign(jwt, secret);

            return jwt;
        }


        public static string Base64Encode(dynamic obj)
        {
            Type strType = obj.GetType();

            var base64EncodedValue = Convert.ToBase64String(strType.Name.ToLower() == "string" ? Encoding.UTF8.GetBytes(obj) : obj);
            return base64EncodedValue;
        }


        private static string Sign(string str, string key)
        {


            byte[] signature;

            using (var crypto = new HMACSHA256(Encoding.UTF8.GetBytes(key)))
            {
                signature = crypto.ComputeHash(Encoding.UTF8.GetBytes(str));
            }

            return System.Web.HttpServerUtility.UrlTokenEncode(signature);

        }

    }


    public class Header
    {
        public string alg { get; set; }
        public string typ { get; set; }
    }

    public class JwtPayload
    {
        public string appkey { get; set; }
        public string resource { get; set; }
    }


}

首先,CreateToken方法传递凭据以创建有效负载。然后它调用EncodeToken方法,该方法将有效负载和机密作为参数。请记住,我的秘密是一个硬编码的字符串,在整个应用程序的生命周期内永远不会改变;所以我知道这不会随机生成数字1.

第39行,标题和有效负载转换为基本64字符串,并通过一个点连接在一起,完全生成令牌的前两部分:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBrZXkiOiIxMjMtNDU2LTc4OS0wIiwicmVzb3VyY2UiOiJnZXRfZ2VvY29kZSJ9

然后,我在第41行调用Sign方法,该方法使用SHA256算法请求签署我的令牌。

Sign方法接受组合的头和有效负载作为str,然后秘密作为密钥传递。

在第62行,我开始使用我的自定义键创建签名,这是" testsecret"。

然后,我在返回之前对第67行的签名进行URL编码。当我将它返回时,第41行将令牌的三个部分组合在一起,从而为我留下了完美的JWT ......除了数字" 1"在秘密的最右端。

请帮忙。

1 个答案:

答案 0 :(得分:1)

HttpServerUtility.UrlTokenEncode的工作方式有关,强调我的:

  

使用基数为64的数字将字节数组编码为等效的字符串表示,可用于在URL上传输

您知道根据其长度,Base64字符串将填充=附加到末尾。 =不被视为URL安全,因此将替换为表示计数的整数,在本例中为1

您可以通过调试并替换下面的行来测试...

return System.Web.HttpServerUtility.UrlTokenEncode(signature);

......有了......

return Convert.ToBase64String(signature);

...并检查返回值。

您会看到它以=结尾,因此HttpServerUtility.UrlTokenEncode会将其替换为1