JWT簡(jiǎn)介

圖片.png

前言

JSON Web Token(JWT)是目前最流行的跨域身份驗(yàn)證解決方案夫植。微服務(wù)常見(jiàn)的認(rèn)證方案

一泊业、跨域認(rèn)證的問(wèn)題

互聯(lián)網(wǎng)服務(wù)離不開(kāi)用戶認(rèn)證。一般流程是下面這樣都哭。

  • 1秩伞、用戶向服務(wù)器發(fā)送用戶名和密碼逞带。

  • 2、服務(wù)器驗(yàn)證通過(guò)后纱新,在當(dāng)前對(duì)話(session)里面保存相關(guān)數(shù)據(jù)展氓,比如用戶角色、登錄時(shí)間等等脸爱。

  • 3遇汞、服務(wù)器向用戶返回一個(gè) session_id,寫(xiě)入用戶的 Cookie簿废。

  • 4空入、用戶隨后的每一次請(qǐng)求,都會(huì)通過(guò) Cookie族檬,將 session_id 傳回服務(wù)器歪赢。

  • 5、服務(wù)器收到 session_id单料,找到前期保存的數(shù)據(jù)轨淌,由此得知用戶的身份。

這種模式的問(wèn)題在于看尼,擴(kuò)展性(scaling)不好递鹉。單機(jī)當(dāng)然沒(méi)有問(wèn)題,如果是服務(wù)器集群藏斩,或者是跨域的服務(wù)導(dǎo)向架構(gòu)躏结,就要求 session 數(shù)據(jù)共享,每臺(tái)服務(wù)器都能夠讀取 session狰域。

一種解決方案是 session 數(shù)據(jù)持久化媳拴,寫(xiě)入數(shù)據(jù)庫(kù)或別的持久層。各種服務(wù)收到請(qǐng)求后兆览,都向持久層請(qǐng)求數(shù)據(jù)屈溉。這種方案的優(yōu)點(diǎn)是架構(gòu)清晰,缺點(diǎn)是工程量比較大抬探。另外子巾,持久層萬(wàn)一掛了,就會(huì)單點(diǎn)失敗小压。

另一種方案是服務(wù)器索性不保存 session 數(shù)據(jù)了线梗,所有數(shù)據(jù)都保存在客戶端,每次請(qǐng)求都發(fā)回服務(wù)器怠益。JWT 就是這種方案的一個(gè)代表仪搔。

什么是JWT:一句話概括就是(通過(guò)客戶端保存數(shù)據(jù),而服務(wù)器根本不保存會(huì)話數(shù)據(jù)蜻牢,每個(gè)請(qǐng)求都被發(fā)送回服務(wù)器烤咧。)

二偏陪、JWT

JSON Web Token(JWT)是一個(gè)非常輕巧的規(guī)范。這個(gè)規(guī)范允許我們使用JWT在用戶和服務(wù)器之間傳遞安全可靠的信息煮嫌。

一個(gè)JWT實(shí)際上就是一個(gè)字符串竹挡,它由三部分組成,頭部立膛、載荷與簽名揪罕。

1、JWT的原則

JWT的原則是在服務(wù)器身份驗(yàn)證之后宝泵,將生成一個(gè)JSON對(duì)象并將其發(fā)送回用戶好啰,如下所示。

{

     "UserName": "少年閏土",

    "Role": "Admin",

    "Expire": "2019-12-21 09:15:56"

}

以后儿奶,用戶與服務(wù)端通信的時(shí)候框往,都要發(fā)回這個(gè) JSON 對(duì)象。服務(wù)器完全只靠這個(gè)對(duì)象認(rèn)定用戶身份闯捎。為了防止用戶篡改數(shù)據(jù)椰弊,服務(wù)器在生成這個(gè)對(duì)象的時(shí)候,會(huì)加上簽名瓤鼻。

2秉版、JWT的數(shù)據(jù)結(jié)構(gòu)

樣例:

eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1NTc5MDU4MDIsImV4cCI6MTU1NzkwNjgwMiwicm9sZXMiOiJhZG1pbiJ9.AS5Y2fNCwUzQQxXh_QQWMpaB75YqfuK-2P7VZiCXEJI

他是一個(gè)長(zhǎng)字符串,中間用.進(jìn)行分割茬祷,代表JWT的三個(gè)組成部分清焕,如下:

  • Header(頭部)

  • Payload(負(fù)載)

  • Signature(簽名)


    圖片來(lái)自網(wǎng)絡(luò)-僅供參考.png

2.1、頭部(Header)

頭部用于描述關(guān)于該JWT的最基本的信息祭犯,例如其類型以及簽名所用的算法等秸妥。這也可以被表示成一個(gè)JSON對(duì)象。
{"typ":"JWT","alg":"HS256"}

這個(gè)json中的typ屬性沃粗,用來(lái)標(biāo)識(shí)整個(gè)token字符串是一個(gè)JWT字符串粥惧;它的alg屬性,用來(lái)說(shuō)明這個(gè)JWT簽發(fā)的時(shí)候所使用的簽名和摘要算法最盅。typ跟alg屬性的全稱其實(shí)是type跟algorithm突雪,分別是類型跟算法的意思。之所以都用三個(gè)字母來(lái)表示檩禾,也是基于JWT最終字串大小的考慮挂签,同時(shí)也是跟JWT這個(gè)名稱保持一致,這樣就都是三個(gè)字符了…typ跟alg是JWT中標(biāo)準(zhǔn)中規(guī)定的屬性名稱

在頭部指明了簽名算法是HS256算法盼产。 我們進(jìn)行BASE64編碼http://base64.xpcha.com/,編碼后的字符串如下:
eyJhbGciOiJIUzI1NiJ9

2.2勺馆、載荷(Playload)

Payload 部分也是一個(gè) JSON 對(duì)象戏售,用來(lái)存放實(shí)際需要傳遞的數(shù)據(jù)侨核。JWT 規(guī)定了7個(gè)官方字段,供選用灌灾。

iss: jwt簽發(fā)者
sub: jwt所面向的用戶
aud: 接收jwt的一方
exp: jwt的過(guò)期時(shí)間搓译,這個(gè)過(guò)期時(shí)間必須要大于簽發(fā)時(shí)間
nbf: 定義在什么時(shí)間之前,該jwt都是不可用的.
iat: jwt的簽發(fā)時(shí)間
jti: jwt的唯一身份標(biāo)識(shí)锋喜,主要用來(lái)作為一次性token些己。

除了官方字段,你還可以在這個(gè)部分定義私有字段
樣例:
{"sub":"1234567890","name":"John Doe","admin":true}
然后將其進(jìn)行base64加密嘿般,得到Jwt的第二部分段标。
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

圖片.png

2.3、簽名(Signature)

Signature 部分是對(duì)前兩部分的簽名炉奴,防止數(shù)據(jù)篡改逼庞。這個(gè)簽證信息由三部分組成:

header (base64后的)
payload (base64后的)
secret

首先,需要指定一個(gè)密鑰(secret)瞻赶。這個(gè)密鑰只有服務(wù)器才知道赛糟,不能泄露給用戶。這個(gè)部分需要base64加密后的header和base64加密后的payload使用.連接組成的字符串砸逊,然后通過(guò)header中聲明的加密方式進(jìn)行加鹽secret組合加密璧南,然后就構(gòu)成了jwt的第三部分。

    HMACSHA256(
      base64UrlEncode(header) + "." +
      base64UrlEncode(payload),
      secret)

3师逸、Base64URL

前面提到穆咐,Header 和 Payload 串型化的算法是 Base64URL。這個(gè)算法跟 Base64 算法基本類似字旭,但有一些小的不同对湃。

JWT 作為一個(gè)令牌(token),有些場(chǎng)合可能會(huì)放到 URL(比如 api.example.com/?token=xxx)遗淳。Base64 有三個(gè)字符+拍柒、/和=,在 URL 里面有特殊含義屈暗,所以要被替換掉:=被省略拆讯、+替換成-,/替換成_ 养叛。這就是 Base64URL 算法种呐。

4、JWT 的使用方式

客戶端收到服務(wù)器返回的 JWT弃甥,可以儲(chǔ)存在 Cookie 里面爽室,也可以儲(chǔ)存在 localStorage。

此后淆攻,客戶端每次與服務(wù)器通信阔墩,都要帶上這個(gè) JWT嘿架。你可以把它放在 Cookie 里面自動(dòng)發(fā)送,但是這樣不能跨域啸箫,所以更好的做法是放在 HTTP 請(qǐng)求的頭信息Authorization字段里面耸彪。
Authorization: Bearer <token>

下圖顯示了如何獲取JWT并將其用于訪問(wèn)API或資源:


圖片.png

三、JWT使用

1忘苛、添加依賴

       <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.2.0</version>
        </dependency>

2蝉娜、工具類

package com.example.demo.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: 少年閏土
 * @Date: 2019/12/11 
 * @Time: 下午 4:12
 * @Version: v1.0
 * jwt工具類
 */
@Component
public class JwtUtils {

    /**
     * 解析token
     *
     * @param token token
     * @return 用戶名
     */
    public static String getUserName(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("userName").asString();
        } catch (JWTDecodeException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 簽發(fā)token
     *
     * @param userName 用戶名
     * @return token
     */
    public static String sign(String userName,String secret) {
        try {
            //token過(guò)期時(shí)間
            Date date = new Date(System.currentTimeMillis() + (60 * 60 * 1000));
            Algorithm algorithm = Algorithm.HMAC256(secret);
            // 附帶username信息
            return JWT.create()
                    .withClaim("userName", userName)
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 檢驗(yàn)token是否過(guò)期
     *
     * @param token
     * @return
     */
    public static Map verify(String token,String userName, String secret) {
        Map result = new HashMap<String, Object>(2);
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim("userName", userName)
                    .build();
            DecodedJWT jwt = verifier.verify(token);
            result.put("isSuccess", true);
            result.put("exception", null);
        } catch (Exception exception) {
            result.put("isSuccess", false);
            result.put("exception", exception);
        }
        return result;
    }
}

3、使用

    @ApiOperation(value = "瀏覽器點(diǎn)擊登錄")
    @ApiImplicitParam(name = "user", value = "用戶實(shí)體", required = true, paramType = "User")
    @PostMapping("/login")
    public R login(@RequestBody User user) {
        log.debug("------瀏覽器點(diǎn)擊登錄------");
        String userName = user.getUsername();
        String passWord = user.getPassword();
        User u = this.userService.getUser(userName);
        String passWordSalt = MD5.md5Salt(passWord, userName);
        if (u != null && u.getPassword().equals(passWordSalt)) {
            String token = JwtUtils.sign(userName, passWordSalt);
            return R.ok(R.SUCCESS, R.MSG_SUCCESS, token);
        } else {
            return R.error(R.MSG_LOGIN_ERROR);
        }
    }

個(gè)人博客
騰訊云社區(qū)
掘金
CSDN
OSCHINA
公眾號(hào):

wx.jpg

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末扎唾,一起剝皮案震驚了整個(gè)濱河市召川,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌稽屏,老刑警劉巖扮宠,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異狐榔,居然都是意外死亡坛增,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門薄腻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)收捣,“玉大人,你說(shuō)我怎么就攤上這事庵楷“瞻” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵尽纽,是天一觀的道長(zhǎng)咐蚯。 經(jīng)常有香客問(wèn)我,道長(zhǎng)弄贿,這世上最難降的妖魔是什么春锋? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮差凹,結(jié)果婚禮上期奔,老公的妹妹穿的比我還像新娘。我一直安慰自己危尿,他們只是感情好呐萌,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著谊娇,像睡著了一般肺孤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,182評(píng)論 1 299
  • 那天渠旁,我揣著相機(jī)與錄音攀例,去河邊找鬼船逮。 笑死顾腊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的挖胃。 我是一名探鬼主播杂靶,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼酱鸭!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤瓦灶,失蹤者是張志新(化名)和其女友劉穎奶陈,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蔚舀,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡饵沧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了赌躺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狼牺。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖礼患,靈堂內(nèi)的尸體忽然破棺而出是钥,到底是詐尸還是另有隱情,我是刑警寧澤缅叠,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布悄泥,位于F島的核電站,受9級(jí)特大地震影響肤粱,放射性物質(zhì)發(fā)生泄漏弹囚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一狼犯、第九天 我趴在偏房一處隱蔽的房頂上張望余寥。 院中可真熱鬧,春花似錦悯森、人聲如沸宋舷。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)祝蝠。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間绎狭,已是汗流浹背细溅。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留儡嘶,地道東北人喇聊。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蹦狂,于是被迫代替她去往敵國(guó)和親誓篱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

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

  • 轉(zhuǎn)自:https://segmentfault.com/a/1190000005047525?utm_source...
    vv源vv閱讀 1,102評(píng)論 3 47
  • JWT Json web token 適用于分布式站點(diǎn)的單點(diǎn)登錄(SSO)場(chǎng)景 1. 講在前面: 傳統(tǒng)的sessi...
    battleMonkey閱讀 670評(píng)論 0 0
  • JWT 介紹 (https://jwt.io/) JSON Web Token(JWT)是一個(gè)開(kāi)放標(biāo)準(zhǔn)(RFC 7...
    匆匆歲月閱讀 5,569評(píng)論 1 41
  • 銀箭鋁銀漿生產(chǎn)廠家,沒(méi)有中間商賺差價(jià)摆屯,真真正正的給你廠家優(yōu)惠價(jià)邻遏, 花更少的錢買到更優(yōu)質(zhì)的產(chǎn)品,這是每一位顧客想要的...
    小人物121閱讀 118評(píng)論 0 0
  • “仁虐骑、義准验、禮、智富弦、信”是儒家的五常沟娱,也是中國(guó)傳統(tǒng)文化中的核心思想⊥蠊瘢孔子提出“仁济似、義、禮盏缤,孟子延伸為”仁砰蠢、...
    向日葵班閱讀 468評(píng)論 0 0