JWT是什麼 JWT全稱是Json Web Token,是一種用於雙方之間傳遞安全信息的簡潔的、URL安全的表述性聲明規範。JWT作為一個開放的標準( RFC 7519 ),定義了一種簡潔的,自包含的方法用於通信雙方之間以Json對象的形式安全的傳遞信息。因為數字簽名的存在,這些信息是可信的,JWT ...
JWT是什麼
JWT全稱是Json Web Token,是一種用於雙方之間傳遞安全信息的簡潔的、URL安全的表述性聲明規範。JWT作為一個開放的標準( RFC 7519 ),定義了一種簡潔的,自包含的方法用於通信雙方之間以Json對象的形式安全的傳遞信息。因為數字簽名的存在,這些信息是可信的,JWT可以使用HMAC演算法或者是RSA的公私秘鑰對進行簽名。
JWT的結構
JWT一般由三段構成,用.號分隔開,第一段是header,第二段是payload,第三段是signature,例如:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiTXJCdWciLCJleHAiOjE1MTI5NTkzMDMuMCwianRpIjoibHVvemhpcGVuZyJ9.9iwGMHmS0mophyFgliLK15hs_eE770IchaZ-bWcX5c0
1、header
jwt的頭部承載兩部分信息:
聲明類型。這裡是jwt
聲明加密的演算法。通常直接使用 HMAC SHA256,其它還有RS256等
完整的頭部就像下麵這樣的JSON:
{ "alg": "HS256", "typ": "JWT" }
然後將頭部進行base64加密(該加密是可以對稱解密的),構成了第一部分
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
2、playload
載荷就是存放有效信息的地方。這個名字像是特指飛機上承載的貨品,這些有效信息包含三個部分:
標準中註冊的聲明
公共的聲明
私有的聲明
標準中註冊的聲明 (建議但不強制使用) :
iss : jwt簽發者
sub:jwt所面向的用戶
aud:接收jwt的一方
exp:jwt的過期時間,這個過期時間必須要大於簽發時間
nbf:定義在什麼時間之前,該jwt都是不可用的.
iat :jwt的簽發時間
jti :jwt的唯一身份標識,主要用來作為一次性token,從而迴避重放攻擊。
公共的聲明 :
公共的聲明可以添加任何的信息,一般添加用戶的相關信息或其他業務需要的必要信息.但不建議添加敏感信息,因為該部分在客戶端可解密.
私有的聲明 :
私有聲明是提供者和消費者所共同定義的聲明,一般不建議存放敏感信息,因為base64是對稱解密的,意味著該部分信息可以歸類為明文信息。
定義一個playload
{ "name": "MrBug", "exp": 1512959303, "jti": "luozhipeng" }
然後將其進行base64加密,得到Jwt的第二部分
eyJuYW1lIjoiTXJCdWciLCJleHAiOjE1MTI5NTkzMDMuMCwianRpIjoibHVvemhpcGVuZyJ9
3、signature
jwt的第三部分是一個簽證信息,這個簽證信息由三部分組成:
header (base64後的)
payload (base64後的)
secret
這個部分需要base64加密後的header和base64加密後的payload使用.連接組成的字元串,然後通過header中聲明的加密方式進行加secret組合加密,然後就構成了jwt的第三部分。
// javascript var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload); var signature = HMACSHA256(encodedString, 'secret'); // 9iwGMHmS0mophyFgliLK15hs_eE770IchaZ-bWcX5c0
將這三部分用.連接成一個完整的字元串,構成了最終的jwt:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiTXJCdWciLCJleHAiOjE1MTI5NTkzMDMuMCwianRpIjoibHVvemhpcGVuZyJ9.9iwGMHmS0mophyFgliLK15hs_eE770IchaZ-bWcX5c0
註意:secret是保存在伺服器端的,jwt的簽發生成也是在伺服器端的,secret就是用來進行jwt的簽發和jwt的驗證,所以,它就是你服務端的私鑰,在任何場景都不應該流露出去。一旦客戶端得知這個secret, 那就意味著客戶端是可以自我簽發jwt了。
如何應用
一般是在請求頭裡加入Authorization,並加上Bearer標註:
fetch('api/user/1', { headers: { 'Authorization': 'Bearer ' + token } })
服務端會驗證token,如果驗證通過就會返回相應的資源。整個流程就是這樣的:
安全相關
不應該在jwt的payload部分存放敏感信息,因為該部分是客戶端可解密的部分。
保護好secret私鑰,該私鑰非常重要。
如果可以,請使用https協議
如何在.net中使用
這裡要用到一個JWT.NET的第三方庫,可以通過NuGet的方式獲取,目前最新版是3.1.1,最新版只支持.net framework4.6及以上,如圖
因為,我項目中用的是.net framework4.5,所以我安裝的是JWT.NET 3.0.0,你可以使用VS 工具 / NuGet包管理器 / 程式包管理器控制台 ,輸入以下命令手動安裝
Install-Package JWT -Version 3.0.0
1、創建token,此處,我們只需要自定義payload和secrect密鑰即可,可生成三段格式的字元串
IDateTimeProvider provider = new UtcDateTimeProvider(); var now = provider.GetNow(); var unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); // or use JwtValidator.UnixEpoch var secondsSinceEpoch = Math.Round((now - unixEpoch).TotalSeconds); var payload = new Dictionary<string, object> { { "name", "MrBug" }, {"exp",secondsSinceEpoch+100 }, {"jti","luozhipeng" } }; Console.WriteLine(secondsSinceEpoch); IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); IJsonSerializer serializer = new JsonNetSerializer(); IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder); var token = encoder.Encode(payload, secret); Console.WriteLine(token);
2、token解密
try { IJsonSerializer serializer = new JsonNetSerializer(); IDateTimeProvider provider = new UtcDateTimeProvider(); IJwtValidator validator = new JwtValidator(serializer, provider); IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder); var json = decoder.Decode(token, secret, verify: true);//token為之前生成的字元串 Console.WriteLine(json); } catch (TokenExpiredException) { Console.WriteLine("Token has expired"); } catch (SignatureVerificationException) { Console.WriteLine("Token has invalid signature"); }
3、自定義json解析器,只要繼承IJsonSerializer介面
public class CustomJsonSerializer : IJsonSerializer { public string Serialize(object obj) { // Implement using favorite JSON Serializer } public T Deserialize<T>(string json) { // Implement using favorite JSON Serializer } }
使用
IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); IJsonSerializer serializer = new CustomJsonSerializer(); IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
4、自定義JSON序列化
預設的JSON序列化由JsonNetSerializer完成,可以自定義序列化:
JsonSerializer customJsonSerializer = new JsonSerializer { // All json keys start with lowercase characters instead of the exact casing of the model/property. e.g. fullName ContractResolver = new CamelCasePropertyNamesContractResolver(), // Nice and easy to read, but you can also do Formatting.None to reduce the payload size (by hardly anything...) Formatting = Formatting.Indented, // The best date/time format/standard. DateFormatHandling = DateFormatHandling.IsoDateFormat, // Don't add key/values when the value is null. NullValueHandling = NullValueHandling.Ignore, // Use the enum string-value, not the implicit int value, e.g. "oolor" : "red" Converters.Add(new StringEnumConverter()) }; IJsonSerializer serializer = new JsonNetSerializer(customJsonSerializer);
整理自:
https://github.com/jwt-dotnet/jwt
http://www.jianshu.com/p/576dbf44b2ae