成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

關(guān)于 jwt 你應(yīng)該知道的事情

leone / 3200人閱讀

摘要:頭部需要一個(gè)頭部,用于描述關(guān)于該的最基本的信息,例如其類型以及簽名所用的算法等。簽發(fā)者需要準(zhǔn)備一個(gè)可以確認(rèn)自己身份的字符串,這個(gè)字符串我們稱之為。

什么是 jwt ?

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

jwt 使用場景

jwt 用圖廣泛,例如授權(quán)、鑒權(quán)等。具體一點(diǎn)的話,假如我們有一個(gè) A 用戶想要邀請某用戶進(jìn)入自己的群組,此時(shí) A 用戶需要生成一條邀請鏈接,鏈接內(nèi)容大致如下: https://host/group/{group_id}/invite/{invite_user}

此時(shí)這個(gè)鏈接點(diǎn)擊進(jìn)去雖然可以實(shí)現(xiàn)讓用戶加入群組,但是用戶可以隨意更改這個(gè)鏈接的參數(shù),例如改改 group 后面的ID,從而加入其他任意群組,改改 invite 后面的邀請人等等操作。所以這種 URL 并不是安全的,那么這種情況下,我們就可以使用 jwt 來實(shí)創(chuàng)建一個(gè)安全的邀請鏈接了。

首先 URL 要簡單改一下, https://host/group/invite/{token}
可以看到我們?nèi)サ袅?groupId 和 inviteUser 參數(shù),添加了一個(gè) token 參數(shù),可想而知, groupId 和 inviteUser 應(yīng)該是被包含進(jìn) token 里面了,如何實(shí)現(xiàn)這個(gè)看似很神奇的 token 呢? 我們來看看 jwt 的原理吧。

jwt 的組成、原理及實(shí)現(xiàn)

在講 jwt 原理之前得先知道 jwt 由哪些東西組成。

jwt 組成

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

頭部 (Header)

JWT 需要一個(gè)頭部,用于描述關(guān)于該 JWT 的最基本的信息,例如其類型以及簽名所用的算法等。這也可以被表示成一個(gè) JSON 對象,如:

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

將上面的 json 字符串使用 base64 進(jìn)行編碼后,可以得到一下內(nèi)容,我們稱其為 JWT 的頭部(Header)。

eyJ0eXAiOiJqd3QiLCJhbGciOiJtZDUifQ==
載荷(Payload)

我們先將上面的邀請入群的操作描述成一個(gè) JSON 對象。其中添加了一些其他的信息,幫助今后收到這個(gè) JWT 的服務(wù)器理解這個(gè)JWT。

{
    "sub": "1",
    "iss": "http://host/group/invite",
    "iat": 1451888119,
    "exp": 1454516119,
    "nbf": 1451888119,
    "jti": "37c107e4609ddbcc9c096ea5ee76c667",
    "group_id": 1,
    "invite_user": "A"
}

這里面的前6個(gè)字段都是由JWT的標(biāo)準(zhǔn)所定義的。

sub: 該 JWT 所面向的用戶

iss: 該 JWT 的簽發(fā)者

iat(issued at): 在什么時(shí)候簽發(fā)的 token

exp(expires): token 什么時(shí)候過期

nbf(not before):token 在此時(shí)間之前不能被接收處理

jti:JWT ID為web token 提供唯一標(biāo)識

將上面的 json 字符串使用 base64 進(jìn)行編碼后,可以得到一下內(nèi)容,我們稱其為 JWT 的載荷(Payload)。

eyJzdWIiOiIxIiwiaXNzIjoiaHR0cDpcL1wvOiIsImV4cCI6MTUyNzY2NzY2MywiaWF0IjoxNTI3NjY0MDYzLCJuYmYiOjE1Mjc2NjQwNjMsImdyb3VwX2lkIjoxLCJpbnZpdGVfdXNlciI6IkEiLCJqdGkiOiJlMjE4ZTJhZDdlYTdmZjUzYTVhM2RlZjA0MmFjMjM4NCJ9
簽名(Signature)

在簽名之前我們需要先得到用于簽名的字符串, 將頭部和載荷使用 . 進(jìn)行拼接(頭部在前), 得到用于簽名的字符串

eyJ0eXAiOiJqd3QiLCJhbGciOiJtZDUifQ==.eyJzdWIiOiIxIiwiaXNzIjoiaHR0cDpcL1wvOiIsImV4cCI6MTUyNzY2NzY2MywiaWF0IjoxNTI3NjY0MDYzLCJuYmYiOjE1Mjc2NjQwNjMsImdyb3VwX2lkIjoxLCJpbnZpdGVfdXNlciI6IkEiLCJqdGkiOiJlMjE4ZTJhZDdlYTdmZjUzYTVhM2RlZjA0MmFjMjM4NCJ9

然后使用簽名方法對用于簽名的字符串進(jìn)行簽名, 得到如下字符串,即 簽名(Signature)

NDljMzljOTkyOGNmYWU1NGEyZDYzMTk5NTNlNGEwZDA=

最后把用于簽名的字符串和簽名使用 . 進(jìn)行拼接(簽名在后), 即可得到 一個(gè)完整的 token。但是,此時(shí)的
token 沒有帶上簽發(fā)者特有的標(biāo)志,是可以被偽造的,至于如何解決這個(gè)問題我們下面 jwt 具體實(shí)現(xiàn)會(huì)講。

jwt 原理 jwt 如何保證安全 ?

上面說完 jwt 組成,相信你已經(jīng)知道 jwt 大概是個(gè)啥子?xùn)|西了 --- 就是一個(gè)字符串!!!
那么這個(gè)字符串如何保證不被篡改呢 ? 這里就要引入 secret 了。

回到上面的例子,邀請用戶入群這個(gè)場景,雖然我們上面把 參數(shù)改成了 token 這種形式,但是你可能會(huì)發(fā)現(xiàn),這樣的 token 別人捕獲了之后,任然可以自己偽造一個(gè)類似的 token ,因?yàn)榇藭r(shí)的簽名(Signature)并沒有簽發(fā)者特有的身份信息,所有數(shù)據(jù)都是明文的,所以這樣簽名是不安全的,應(yīng)該加上 secret 進(jìn)行簽名。

簽發(fā)者需要準(zhǔn)備一個(gè)可以確認(rèn)自己身份的字符串,這個(gè)字符串我們稱之為 secret 。以 md5 作為簽名方法為例(并不建議使用 md5 作為簽名方法),我們只需要將上面準(zhǔn)備的 用于簽名的字符串簡單的與 secret 進(jìn)行拼接,然后進(jìn)行 md5 計(jì)算,這時(shí)候得到的簽名是受 secret 值影響的,所以即便他人捕獲了之后 token,他仍然不能隨意篡改 token 的內(nèi)容,因?yàn)樗恢?secret 和拼接方法,故此時(shí)的 token 是安全的,不可被惡意篡改的。

$signatureString = "pen"; // 原始數(shù)據(jù)
$secret = "apple";        // 簽發(fā)者 secret

$originSignature = md5($signatureString ."-". $secret);
print_r($signature); // apple-pen 

$signatureString = "pen"; // 原始數(shù)據(jù)
$secret = "pineapple";    // 不一樣的 secret 

$fakeSignature = md5($signatureString ."-". $secret);
print_r($signature); // pineapple-pen 
// 可以看到不一樣的 secret 會(huì)生成完全不一樣的簽名,這樣我們的數(shù)據(jù)就可以保證不能被隨意篡改了~
jwt 傳輸?shù)臄?shù)據(jù)會(huì)泄露 ?

是的,jwt 的頭部和載荷字段都可以被解碼(base64 屬于編碼,是可以被解碼的)。所以并不建議用 jwt 傳輸敏感信息,例如密碼,因?yàn)檫@很容易被捕獲后解碼,從而被竊取。

secret 一個(gè)字符串不足以描述簽發(fā)者信息 ?

我們可以將 簽發(fā)者信息描述成一個(gè) json ,然后對這個(gè) json 字符串進(jìn)行編碼,這樣同樣可以得到一個(gè) secret 字符串。

jwt 實(shí)現(xiàn)

先來一個(gè)最粗暴的 jwt 實(shí)現(xiàn)

最簡單粗暴的 jwt for php 實(shí)現(xiàn)
class JWT
{
    protected $headers;

    protected $payload;

    /**
     * @return array
     */
    public function getHeaders(): array
    {
        return $this->headers;
    }

    /**
     * @return array
     */
    public function getPayload(): array
    {
        return $this->payload;
    }

    public function __construct(array $headers, array $payload)
    {
        $this->setHeaders($headers);
        $this->setPayload($payload);
    }

    public function setHeaders(array $headers): void
    {
        $this->headers = $headers;
    }

    public function setPayload(array $payload): void
    {
        $this->payload = $payload;
    }

    /**
     * 獲取用于簽名的字符串
     *
     * @return string
     */
    public function signatureStr(): string
    {
        $headersStr = $this::encodeStr(json_encode($this->headers));
        $payloadStr = $this::encodeStr(json_encode($this->payload));

        return "{$headersStr}.{$payloadStr}";
    }

    /**
     * 編碼
     *
     * @param string $string
     *
     * @return string
     */
    protected static function encodeStr(string $string): string
    {
        return rtrim(strtr(base64_encode($string), "+/", "-_"), "=");
    }

    /**
     * 解碼
     *
     * @param string $string
     *
     * @return string
     */
    protected static function decodeStr(string $string): string
    {
        return base64_decode(strtr($string, "-_", "+/"));
    }

    /**
     * 簽名,此時(shí)的 secret 為 qbhy
     *
     * @param string $string
     *
     * @return string
     */
    protected static function signature(string $string): string
    {
        return md5($string . "qbhy");
    }

    /**
     * 校驗(yàn)簽名
     *
     * @param string $signStr
     * @param string $sign
     *
     * @return bool
     */
    protected static function checkSignature(string $signStr, string $sign): bool
    {
        return static::signature($signStr) === $sign;
    }

    /**
     * 生成 token
     *
     * @return string
     */
    public function token(): string
    {
        $signStr = $this->signatureStr();

        $token = $signStr . "." . $this::signature($signStr);

        return $token;
    }

    /**
     * 從 token 中獲取數(shù)據(jù)
     *
     * @param string $token
     *
     * @return AppModulesJWTJWT
     * @throws AppModulesJWTJWTException
     */
    public static function fromToken(string $token): JWT
    {
        $arr = explode(".", $token);

        if (count($arr) !== 3) {
            throw new JWTException("token 錯(cuò)誤");
        }

        if (!static::checkSignature("{$arr[0]}.{$arr[1]}", $arr[2])) {
            throw new JWTException("簽名錯(cuò)誤");
        }

        $headers = json_decode(static::decodeStr($arr[0]), true);
        $payload = json_decode(static::decodeStr($arr[1]), true);

        return new static($headers, $payload);
    }

}
simple-jwt

這里先安利一下我寫的一個(gè)基于 php 的 jwt 擴(kuò)展包 --- 96qbhy/simple-jwt , 這個(gè)包實(shí)現(xiàn)了完整的 jwt 規(guī)范,開箱即用,你可以基于 96qbhy/simple-jwt 來給你的應(yīng)用添加 jwt 相關(guān)功能。

我把 simple-jwt 拆分成,Encoder(編碼器)Encrypter(簽名器) 、JWT、JWTManager 四部分,你可以自行擴(kuò)展 Encoder、Encrypter,從而實(shí)現(xiàn)自己的編碼和加密方法,感興趣的同學(xué)可以去 github 看看源碼 96qbhy/simple-jwt 。有問題歡迎與我討論,同時(shí)歡迎 IssuePR 。
如有錯(cuò)誤歡迎指出,謝謝。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/28719.html

相關(guān)文章

  • 前端應(yīng)該知道web登錄

    摘要:客戶端發(fā)起非登錄請求時(shí),服務(wù)端通過中的找到對應(yīng)的來知道此次請求是誰發(fā)出的。數(shù)量隨著登錄用戶的增多而增多,存儲(chǔ)會(huì)增加很多。還記得在上家公司做全干工程師的時(shí)候,基本從頁面寫到運(yùn)維,當(dāng)時(shí)做登錄這塊的時(shí)候,被session、cookie、token各種概念差點(diǎn)整蒙圈了,上網(wǎng)查詢相關(guān)概念,發(fā)現(xiàn)很多人都是類似的疑惑,比如:showImg(https://user-gold-cdn.xitu.io/201...

    NervosNetwork 評論0 收藏0
  • 弄懂JWT原理

    摘要:的組成一個(gè)實(shí)際上就是一個(gè)字符串,它由三部分組成,頭部載荷與簽名。這個(gè)字符串我們將它稱作的載荷。注意是一種編碼,它是可以被翻譯回原來的樣子來的。這也可以被表示成一個(gè)對象。 JSON Web Token(JWT)是一個(gè)非常輕巧的規(guī)范。這個(gè)規(guī)范允許我們使用JWT在用戶和服務(wù)器之間傳遞安全可靠的信息。 讓我們來假想一下一個(gè)場景。在A用戶關(guān)注了B用戶的時(shí)候,系統(tǒng)發(fā)郵件給B用戶,并且附有一個(gè)鏈接點(diǎn)...

    animabear 評論0 收藏0
  • 編寫 Node.js Rest API 10 個(gè)最佳實(shí)踐

    摘要:要對進(jìn)行黑盒測試測試的最好辦法是對他們進(jìn)行黑盒測試,黑盒測試是一種不關(guān)心應(yīng)用內(nèi)部結(jié)構(gòu)和工作原理的測試方法,測試時(shí)系統(tǒng)任何部分都不應(yīng)該被。此外,有了黑盒測試并不意味著不需要單元測試,針對的單元測試還是需要編寫的。 本文首發(fā)于之乎專欄前端周刊,全文共 6953 字,讀完需 8 分鐘,速度需 2 分鐘。翻譯自:RingStack 的文章 https://blog.risingstack.co...

    ermaoL 評論0 收藏0
  • 微服務(wù)實(shí)戰(zhàn):從架構(gòu)到發(fā)布(二)

    摘要:微服務(wù)架構(gòu)著重培養(yǎng)通用可重用的服務(wù)。服務(wù)注冊和發(fā)現(xiàn)微服務(wù)架構(gòu)下,有大量的微服務(wù)需要處理。網(wǎng)關(guān)也是獲得微服務(wù)狀態(tài)監(jiān)控信息的中心。實(shí)際情況是,微服務(wù)和其它企業(yè)架構(gòu)并存。 引言:上篇文章介紹了微服務(wù)和單體架構(gòu)的區(qū)別、微服務(wù)的設(shè)計(jì)、消息、服務(wù)間通信、數(shù)據(jù)去中心化,本篇會(huì)繼續(xù)深入微服務(wù),介紹其它特性。 治理去中心化 通常治理的意思是構(gòu)建方案,并且迫使人們通過努力達(dá)到組織的目標(biāo)。SOA治理指導(dǎo)開發(fā)...

    JinB 評論0 收藏0
  • 微服務(wù)實(shí)戰(zhàn):從架構(gòu)到發(fā)布(二)

    摘要:微服務(wù)架構(gòu)著重培養(yǎng)通用可重用的服務(wù)。服務(wù)注冊和發(fā)現(xiàn)微服務(wù)架構(gòu)下,有大量的微服務(wù)需要處理。網(wǎng)關(guān)也是獲得微服務(wù)狀態(tài)監(jiān)控信息的中心。實(shí)際情況是,微服務(wù)和其它企業(yè)架構(gòu)并存。 引言:上篇文章介紹了微服務(wù)和單體架構(gòu)的區(qū)別、微服務(wù)的設(shè)計(jì)、消息、服務(wù)間通信、數(shù)據(jù)去中心化,本篇會(huì)繼續(xù)深入微服務(wù),介紹其它特性。 治理去中心化 通常治理的意思是構(gòu)建方案,并且迫使人們通過努力達(dá)到組織的目標(biāo)。SOA治理指導(dǎo)開發(fā)...

    zhaot 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<