1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        基于jwt的token驗證、原理及流程

        共 8542字,需瀏覽 18分鐘

         ·

        2021-09-13 22:03

        來源:www.cnblogs.com/better-farther-world2099

        一、什么是JWT

        Json web token (JWT), 是為了在網(wǎng)絡(luò)應(yīng)用環(huán)境間傳遞聲明而執(zhí)行的一種基于JSON的開放標(biāo)準(zhǔn)((RFC 7519).

        該token被設(shè)計為緊湊且安全的,特別適用于分布式站點的單點登錄(SSO)場景。

        JWT的聲明一般被用來在身份提供者和服務(wù)提供者間傳遞被認(rèn)證的用戶身份信息,以便于從資源服務(wù)器獲取資源,也可以增加一些額外的其它業(yè)務(wù)邏輯所必須的聲明信息,該token也可直接被用于認(rèn)證,也可被加密。

        二、JWT的組成

        1、JWT生成編碼后的樣子

        eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.UQmqAUhUrpDVV2ST7mZKyLTomVfg7sYkEjmdDI5XF8Q

        2、JWT由三部分構(gòu)成

        第一部分我們稱它為頭部(header),第二部分我們稱其為載荷(payload, 類似于飛機上承載的物品),第三部分是簽證(signature).

        header

        jwt的頭部承載兩部分信息:

        • 聲明類型,這里是jwt
        • 聲明加密的算法 通常直接使用 HMAC SHA256

        完整的頭部就像下面這樣的JSON:

        {
          'typ''JWT',
          'alg''HS256'
        }

        然后將頭部進(jìn)行base64加密(該加密是可以對稱解密的),構(gòu)成了第一部分

        eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

        playload

        載荷就是存放有效信息的地方。這個名字像是特指飛機上承載的貨品,這些有效信息包含三個部分

        • 標(biāo)準(zhǔn)中注冊的聲明
        • 公共的聲明
        • 私有的聲明

        標(biāo)準(zhǔn)中注冊的聲明 (建議但不強制使用) :

        • iss: jwt簽發(fā)者
        • sub: jwt所面向的用戶
        • aud: 接收jwt的一方
        • exp: jwt的過期時間,這個過期時間必須要大于簽發(fā)時間
        • nbf: 定義在什么時間之前,該jwt都是不可用的.
        • iat: jwt的簽發(fā)時間
        • jti: jwt的唯一身份標(biāo)識,主要用來作為一次性token,從而回避重放攻擊。

        公共的聲明 :

        公共的聲明可以添加任何的信息,一般添加用戶的相關(guān)信息或其他業(yè)務(wù)需要的必要信息.但不建議添加敏感信息,因為該部分在客戶端可解密.

        私有的聲明 :

        私有聲明是提供者和消費者所共同定義的聲明,一般不建議存放敏感信息,因為base64是對稱解密的,意味著該部分信息可以歸類為明文信息。

        定義一個payload:

        {
          "sub""1234567890",
          "name""John Doe",
          "admin"true
        }

        然后將其進(jìn)行base64加密,得到Jwt的第二部分

        eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

        signature

        jwt的第三部分是一個簽證信息,這個簽證信息由三部分組成:

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

        這個部分需要base64加密后的header和base64加密后的payload使用.連接組成的字符串(頭部在前),然后通過header中聲明的加密方式進(jìn)行加鹽secret組合加密,然后就構(gòu)成了jwt的第三部分。

        UQmqAUhUrpDVV2ST7mZKyLTomVfg7sYkEjmdDI5XF8Q

        密鑰secret是保存在服務(wù)端的,服務(wù)端會根據(jù)這個密鑰進(jìn)行生成token和驗證,所以需要保護(hù)好。

        3、簽名的目的

        最后一步簽名的過程,實際上是對頭部以及載荷內(nèi)容進(jìn)行簽名。一般而言,加密算法對于不同的輸入產(chǎn)生的輸出總是不一樣的。對于兩個不同的輸入,產(chǎn)生同樣的輸出的概率極其地?。ㄓ锌赡鼙任页墒澜缡赘坏母怕蔬€小)。所以,我們就把“不一樣的輸入產(chǎn)生不一樣的輸出”當(dāng)做必然事件來看待吧。

        所以,如果有人對頭部以及載荷的內(nèi)容解碼之后進(jìn)行修改,再進(jìn)行編碼的話,那么新的頭部和載荷的簽名和之前的簽名就將是不一樣的。而且,如果不知道服務(wù)器加密的時候用的密鑰的話,得出來的簽名也一定會是不一樣的。

        服務(wù)器應(yīng)用在接受到JWT后,會首先對頭部和載荷的內(nèi)容用同一算法再次簽名。那么服務(wù)器應(yīng)用是怎么知道我們用的是哪一種算法呢?別忘了,我們在JWT的頭部中已經(jīng)用alg字段指明了我們的加密算法了。

        如果服務(wù)器應(yīng)用對頭部和載荷再次以同樣方法簽名之后發(fā)現(xiàn),自己計算出來的簽名和接受到的簽名不一樣,那么就說明這個Token的內(nèi)容被別人動過的,我們應(yīng)該拒絕這個Token,返回一個HTTP 401 Unauthorized響應(yīng)。

        注意:在JWT中,不應(yīng)該在載荷里面加入任何敏感的數(shù)據(jù),比如用戶的密碼。

        4、如何應(yīng)用

        一般是在請求頭里加入Authorization,并加上Bearer標(biāo)注:

        fetch('api/user/1', {
          headers: {
            'Authorization''Bearer ' + token
          }
        })

        服務(wù)端會驗證token,如果驗證通過就會返回相應(yīng)的資源。

        5、安全相關(guān)

        • 不應(yīng)該在jwt的payload部分存放敏感信息,因為該部分是客戶端可解密的部分。
        • 保護(hù)好secret私鑰,該私鑰非常重要。
        • 如果可以,請使用https協(xié)議

        6、對Token認(rèn)證的五點認(rèn)識

        • 一個Token就是一些信息的集合;
        • 在Token中包含足夠多的信息,以便在后續(xù)請求中減少查詢數(shù)據(jù)庫的幾率;
        • 服務(wù)端需要對cookie和HTTP Authrorization Header進(jìn)行Token信息的檢查;
        • 基于上一點,你可以用一套token認(rèn)證代碼來面對瀏覽器類客戶端和非瀏覽器類客戶端;
        • 因為token是被簽名的,所以我們可以認(rèn)為一個可以解碼認(rèn)證通過的token是由我們系統(tǒng)發(fā)放的,其中帶的信息是合法有效的;

        三、傳統(tǒng)的session認(rèn)證

        我們知道,http協(xié)議本身是一種無狀態(tài)的協(xié)議,而這就意味著如果用戶向我們的應(yīng)用提供了用戶名和密碼來進(jìn)行用戶認(rèn)證,那么下一次請求時,用戶還要再一次進(jìn)行用戶認(rèn)證才行,因為根據(jù)http協(xié)議,我們并不能知道是哪個用戶發(fā)出的請求,所以為了讓我們的應(yīng)用能識別是哪個用戶發(fā)出的請求,我們只能在服務(wù)器存儲一份用戶登錄的信息,這份登錄信息會在響應(yīng)時傳遞給瀏覽器,告訴其保存為cookie,以便下次請求時發(fā)送給我們的應(yīng)用,這樣我們的應(yīng)用就能識別請求來自哪個用戶了,這就是傳統(tǒng)的基于session認(rèn)證。

        但是這種基于session的認(rèn)證使應(yīng)用本身很難得到擴展,隨著不同客戶端用戶的增加,獨立的服務(wù)器已無法承載更多的用戶,而這時候基于session認(rèn)證應(yīng)用的問題就會暴露出來。

        基于session認(rèn)證所顯露的問題

        Session: 每個用戶經(jīng)過我們的應(yīng)用認(rèn)證之后,我們的應(yīng)用都要在服務(wù)端做一次記錄,以方便用戶下次請求的鑒別,通常而言session都是保存在內(nèi)存中,而隨著認(rèn)證用戶的增多,服務(wù)端的開銷會明顯增大。

        擴展性: 用戶認(rèn)證之后,服務(wù)端做認(rèn)證記錄,如果認(rèn)證的記錄被保存在內(nèi)存中的話,這意味著用戶下次請求還必須要請求在這臺服務(wù)器上,這樣才能拿到授權(quán)的資源,這樣在分布式的應(yīng)用上,相應(yīng)的限制了負(fù)載均衡器的能力。這也意味著限制了應(yīng)用的擴展能力。

        CSRF: 因為是基于cookie來進(jìn)行用戶識別的, cookie如果被截獲,用戶就會很容易受到跨站請求偽造的攻擊。

        基于token的鑒權(quán)機制

        基于token的鑒權(quán)機制類似于http協(xié)議也是無狀態(tài)的,它不需要在服務(wù)端去保留用戶的認(rèn)證信息或者會話信息。這就意味著基于token認(rèn)證機制的應(yīng)用不需要去考慮用戶在哪一臺服務(wù)器登錄了,這就為應(yīng)用的擴展提供了便利。

        流程上是這樣的:

        • 用戶使用用戶名密碼來請求服務(wù)器
        • 服務(wù)器進(jìn)行驗證用戶的信息
        • 服務(wù)器通過驗證發(fā)送給用戶一個token
        • 客戶端存儲token,并在每次請求時附送上這個token值
        • 服務(wù)端驗證token值,并返回數(shù)據(jù)

        這個token必須要在每次請求時傳遞給服務(wù)端,它應(yīng)該保存在請求頭里, 另外,服務(wù)端要支持CORS(跨來源資源共享)策略,一般我們在服務(wù)端這么做就可以了 Access-Control-Allow-Origin:*。

        四、token的優(yōu)點

        • 支持跨域訪問: Cookie是不允許垮域訪問的,這一點對Token機制是不存在的,前提是傳輸?shù)挠脩粽J(rèn)證信息通過HTTP頭傳輸。
        • 無狀態(tài)(也稱:服務(wù)端可擴展行):Token機制在服務(wù)端不需要存儲session信息,因為Token 自身包含了所有登錄用戶的信息,只需要在客戶端的cookie或本地介質(zhì)存儲狀態(tài)信息。
        • 更適用CDN: 可以通過內(nèi)容分發(fā)網(wǎng)絡(luò)請求你服務(wù)端的所有資料(如:javascript,HTML,圖片等),而你的服務(wù)端只要提供API即可。
        • 去耦: 不需要綁定到一個特定的身份驗證方案。Token可以在任何地方生成,只要在你的API被調(diào)用的時候,你可以進(jìn)行Token生成調(diào)用即可。
        • 更適用于移動應(yīng)用: 當(dāng)你的客戶端是一個原生平臺(iOS, Android,Windows 8等)時,Cookie是不被支持的(你需要通過Cookie容器進(jìn)行處理),這時采用Token認(rèn)證機制就會簡單得多。
        • CSRF:因為不再依賴于Cookie,所以你就不需要考慮對CSRF(跨站請求偽造)的防范。
        • 性能: 一次網(wǎng)絡(luò)往返時間(通過數(shù)據(jù)庫查詢session信息)總比做一次HMACSHA256計算 的Token驗證和解析要費時得多。
        • 不需要為登錄頁面做特殊處理: 如果你使用Protractor 做功能測試的時候,不再需要為登錄頁面做特殊處理。
        • 基于標(biāo)準(zhǔn)化:你的API可以采用標(biāo)準(zhǔn)化的 JSON Web Token (JWT). 這個標(biāo)準(zhǔn)已經(jīng)存在多個后端庫(.NET, Ruby, Java,Python, PHP)和多家公司的支持(如:Firebase,Google, Microsoft)。
        • 因為json的通用性,所以JWT是可以進(jìn)行跨語言支持的,像JAVA,JavaScript,NodeJS,PHP等很多語言都可以使用。
        • 因為有了payload部分,所以JWT可以在自身存儲一些其他業(yè)務(wù)邏輯所必要的非敏感信息。
        • 便于傳輸,jwt的構(gòu)成非常簡單,字節(jié)占用很小,所以它是非常便于傳輸?shù)摹?/section>
        • 它不需要在服務(wù)端保存會話信息, 所以它易于應(yīng)用的擴展。

        五、JWT的JAVA實現(xiàn)

        Java中對JWT的支持可以考慮使用JJWT開源庫;JJWT實現(xiàn)了JWT, JWS, JWE 和 JWA RFC規(guī)范;

        下面將簡單舉例說明其使用:

        1、生成Token碼

        import javax.crypto.spec.SecretKeySpec;
        import javax.xml.bind.DatatypeConverter;
        import java.security.Key;
        import io.jsonwebtoken.*;
        import java.util.Date;    
         
        //Sample method to construct a JWT
         
        private String createJWT(String id, String issuer, String subject, long ttlMillis) {
         
        //The JWT signature algorithm we will be using to sign the token
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
         
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
         
        //We will sign our JWT with our ApiKey secret
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(apiKey.getSecret());
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
         
          //Let's set the JWT Claims
        JwtBuilder builder = Jwts.builder().setId(id)
                                        .setIssuedAt(now)
                                        .setSubject(subject)
                                        .setIssuer(issuer)
                                        .signWith(signatureAlgorithm, signingKey);
         
        //if it has been specified, let's add the expiration
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp);
        }
         
        //Builds the JWT and serializes it to a compact, URL-safe string
        return builder.compact();
        }

        2、解碼和驗證Token碼

        import javax.xml.bind.DatatypeConverter;
        import io.jsonwebtoken.Jwts;
        import io.jsonwebtoken.Claims;
         
        //Sample method to validate and read the JWT
        private void parseJWT(String jwt) {
        //This line will throw an exception if it is not a signed JWS (as expected)
        Claims claims = Jwts.parser()        
           .setSigningKey(DatatypeConverter.parseBase64Binary(apiKey.getSecret()))
           .parseClaimsJws(jwt).getBody();
        System.out.println("ID: " + claims.getId());
        System.out.println("Subject: " + claims.getSubject());
        System.out.println("Issuer: " + claims.getIssuer());
        System.out.println("Expiration: " + claims.getExpiration());
        }

        文章整理自:

        • https://blog.csdn.net/buyaoshuohua1/article/details/73739419
        • https://www.cnblogs.com/xiekeli/p/5607107.html#top
        • https://blog.csdn.net/SoftwareOscar/article/details/78538346
        • https://blog.csdn.net/Jack__Frost/article/details/64964208
        • http://blog.leapoahead.com/2015/09/06/understanding-jwt/

        END


        順便給大家推薦一個GitHub項目,這個 GitHub 整理了上千本常用技術(shù)PDF,絕大部分核心的技術(shù)書籍都可以在這里找到,

        GitHub地址:https://github.com/javadevbooks/books

        Gitee地址:https://gitee.com/javadevbooks/books

        電子書已經(jīng)更新好了,你們需要的可以自行下載了,記得點一個star,持續(xù)更新中..



        瀏覽 43
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            大骚屄网 | 国产在线激情视频 | 男女视频免费观看 | 日韩家庭乱伦 | 岳胀耸的雪乳奶水 | 交换做爰在线观看 | 免费观看黄色视频网站 | 成人激情国产上床视频 | 久久久久久久久久99精品 | 亚洲第九十九页 |