ASP.NET Core 2.2 JWT Token(RSA) 使用 (三)

時隔一年了烈疚,窖剑。。捌斧。接上文http://www.reibang.com/p/9c3b6ede9ac8

JWT簽名算法中笛质,一般有兩個選擇,一個采用HS256,另外一個就是采用RS256捞蚂。
參考:http://www.reibang.com/p/cba0dfe4ad4a
RS256 (采用SHA-256 的 RSA 簽名) 是一種非對稱算法, 它使用公共/私鑰對: 標(biāo)識提供方采用私鑰生成簽名, JWT 的使用方獲取公鑰以驗(yàn)證簽名妇押。由于公鑰 (與私鑰相比) 不需要保護(hù), 因此大多數(shù)標(biāo)識提供方使其易于使用方獲取和使用 (通常通過一個元數(shù)據(jù)URL)。
另一方面, HS256 (帶有 SHA-256 的 HMAC 是一種對稱算法, 雙方之間僅共享一個 密鑰姓迅。由于使用相同的密鑰生成簽名和驗(yàn)證簽名, 因此必須注意確保密鑰不被泄密敲霍。

在開發(fā)應(yīng)用的時候啟用JWT俊马,使用RS256更加安全,你可以控制誰能使用什么類型的密鑰肩杈。另外潭袱,如果你無法控制客戶端,無法做到密鑰的完全保密锋恬,RS256會是個更佳的選擇屯换,JWT的使用方只需要知道公鑰。

由于公鑰通秤胙В可以從元數(shù)據(jù)URL節(jié)點(diǎn)獲得彤悔,因此可以對客戶端進(jìn)行進(jìn)行編程以自動檢索公鑰。如果采用這種方式索守,從服務(wù)器上直接下載公鑰信息晕窑,可以有效的減少配置信息。

上文中的token使用的簽名算法是HS256

{ 
  "alg": "HS256", 
  "typ": "JWT" 
} 

這次記錄的是 RS256

{ 
alg: "RS256",
 typ: "JWT"
}

這次記錄主要記錄在ASP.NET Core 中添加jwt token驗(yàn)證的時候使用 RS256算法簽名的token卵佛。
場景就是對接公司的第三方用戶中心杨赤,他們只給了我們一個公鑰。之前沒注意到他們這個token是用的RS256簽名算法截汪,我用上文的HS256的方式來寫疾牲,就一直錯誤。衙解。阳柔。

后來,發(fā)現(xiàn)該用RS256的公鑰去驗(yàn)證簽名蚓峦。

那最重要的就是如何在.NET Core 使用RSA算法 加密\解密\簽名\驗(yàn)證簽名舌剂,找了很多資料,都沒有找到相關(guān)的內(nèi)容暑椰。大部分都是HS256的霍转。沒有找到一個例子是用RSA的。唯一有點(diǎn)相關(guān)的是Identity Server4的一汽,但是Identity Server4已經(jīng)把這個封裝好了(公鑰從endpoint可以獲取到避消,所有使用的時候只需要配置認(rèn)證中心的地址就可以了,封裝了從認(rèn)證中心的url endpoint獲取公鑰驗(yàn)證的過程)角虫。

最后沾谓,就只能從C#的RSA算法入手了。他們給的公鑰是一個字符串,類似

-----BEGIN PUBLIC KEY-----
          MIIBI******************************DAQAB
-----END PUBLIC KEY-----

在上文中戳鹅, 配置簽名驗(yàn)證的地方是

IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["SecurityKey"]))//拿到SecurityKey

那均驶,IssuerSigningKey還可以傳入RsaSecurityKey對象。

通過公鑰的字符串生成RsaSecurityKey在C#中好像沒有直接生成的辦法枫虏。最后參考他人算法妇穴,解決了:
https://gitee.com/bugzerohz/codes/qtbmvg0k64cap2rze8ofn58

public RSA CreateRsaProviderFromPublicKey(string publicKeyString)
{
    // encoded OID sequence for  PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
    byte[] seqOid = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
    byte[] seq = new byte[15];
    var x509Key = Convert.FromBase64String(publicKeyString);
    // ---------  Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob  ------
    using (MemoryStream mem = new MemoryStream(x509Key))
    {
        using (BinaryReader binr = new BinaryReader(mem))  //wrap Memory Stream with BinaryReader for easy reading
        {
            byte bt = 0;
            ushort twobytes = 0;

            twobytes = binr.ReadUInt16();
            if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
                binr.ReadByte();    //advance 1 byte
            else if (twobytes == 0x8230)
                binr.ReadInt16();   //advance 2 bytes
            else
                return null;

            seq = binr.ReadBytes(15);       //read the Sequence OID
            if (!CompareBytearrays(seq, seqOid))    //make sure Sequence for OID is correct
                return null;

            twobytes = binr.ReadUInt16();
            if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81)
                binr.ReadByte();    //advance 1 byte
            else if (twobytes == 0x8203)
                binr.ReadInt16();   //advance 2 bytes
            else
                return null;

            bt = binr.ReadByte();
            if (bt != 0x00)     //expect null byte next
                return null;

            twobytes = binr.ReadUInt16();
            if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
                binr.ReadByte();    //advance 1 byte
            else if (twobytes == 0x8230)
                binr.ReadInt16();   //advance 2 bytes
            else
                return null;

            twobytes = binr.ReadUInt16();
            byte lowbyte = 0x00;
            byte highbyte = 0x00;

            if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81)
                lowbyte = binr.ReadByte();  // read next bytes which is bytes in modulus
            else if (twobytes == 0x8202)
            {
                highbyte = binr.ReadByte(); //advance 2 bytes
                lowbyte = binr.ReadByte();
            }
            else
                return null;
            byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };   //reverse byte order since asn.1 key uses big endian order
            int modsize = BitConverter.ToInt32(modint, 0);

            int firstbyte = binr.PeekChar();
            if (firstbyte == 0x00)
            {   //if first byte (highest order) of modulus is zero, don't include it
                binr.ReadByte();    //skip this null byte
                modsize -= 1;   //reduce modulus buffer size by 1
            }

            byte[] modulus = binr.ReadBytes(modsize);   //read the modulus bytes

            if (binr.ReadByte() != 0x02)            //expect an Integer for the exponent data
                return null;
            int expbytes = (int)binr.ReadByte();        // should only need one byte for actual exponent data (for all useful values)
            byte[] exponent = binr.ReadBytes(expbytes);

            // ------- create RSACryptoServiceProvider instance and initialize with public key -----
            var rsa = RSA.Create();
            RSAParameters rsaKeyInfo = new RSAParameters
            {
                Modulus = modulus,
                Exponent = exponent
            };
            rsa.ImportParameters(rsaKeyInfo);

            return rsa;
        }

    }
}
private bool CompareBytearrays(byte[] a, byte[] b)
{
    if (a.Length != b.Length)
        return false;
    int i = 0;
    foreach (byte c in a)
    {
        if (c != b[i])
            return false;
        i++;
    }
    return true;
}

最后

   //IssuerSigningKey = new RsaSecurityKey(CreateRsaProviderFromPublicKey(publickRsaKey))
            string publickRsaKey = @"MIIB*************AQAB";  // 刪掉公鑰前后的-----BEGIN PUBLIC KEY-----  和 -----END PUBLIC KEY-----
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = false,
                        ValidateAudience = false,
                        ValidateLifetime = true,
                        ValidateIssuerSigningKey = true,
                        IssuerSigningKey = new RsaSecurityKey(CreateRsaProviderFromPublicKey(publickRsaKey))
                    };
                });
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末爬虱,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子腾它,更是在濱河造成了極大的恐慌跑筝,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瞒滴,死亡現(xiàn)場離奇詭異曲梗,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)妓忍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門虏两,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人世剖,你說我怎么就攤上這事定罢。” “怎么了旁瘫?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵祖凫,是天一觀的道長。 經(jīng)常有香客問我酬凳,道長惠况,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任粱年,我火速辦了婚禮售滤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘台诗。我一直安慰自己,他們只是感情好赐俗,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布拉队。 她就那樣靜靜地躺著,像睡著了一般阻逮。 火紅的嫁衣襯著肌膚如雪粱快。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天叔扼,我揣著相機(jī)與錄音事哭,去河邊找鬼。 笑死瓜富,一個胖子當(dāng)著我的面吹牛鳍咱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播与柑,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼谤辜,長吁一口氣:“原來是場噩夢啊……” “哼蓄坏!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起丑念,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤涡戳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后脯倚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體渔彰,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年推正,在試婚紗的時候發(fā)現(xiàn)自己被綠了恍涂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡舔稀,死狀恐怖乳丰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情内贮,我是刑警寧澤产园,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站夜郁,受9級特大地震影響什燕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜竞端,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一屎即、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧事富,春花似錦技俐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至贱勃,卻和暖如春井赌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贵扰。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工仇穗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人戚绕。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓纹坐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親列肢。 傳聞我的和親對象是個殘疾皇子恰画,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容