不用Json web token 還能用什麼?

JSON WEB TOKEN 簡稱 JWT 是如今最經常使用的同樣校驗方式.

他的做用以下

  • jwt是爲了在網絡應用環境傳遞聲明而執行的一種基於json的開放標準。
  • jwt被用來在身份提供者和服務提供者間傳遞被認證的用戶身份信息,簡單來講,就是用
  • 來驗證身份的手段,例如登陸校驗,像咱們以前用的cookie。
  • jwt可使用HMAC算法或者是RSA的公私祕鑰對來進行簽名,來保證信息的可靠性。

應用場景

在例如身份驗證場景中,用戶一旦登陸,接下來的每一個請求都會包含jwt,用來驗證身份信息。因爲通訊雙方使用jwt對數據進行編碼,它的信息是通過簽名的,因此能夠確保信息的安全性.算法

jwt對比cookie

cookie缺點mongodb

  • 客戶端發請求給服務器,服務器種植cookie後,每次請求都會帶上cookie,浪費帶寬
  • cookie不能跨服務器訪問,不支持跨域
  • 服務器要對登陸的用戶對象進行存儲,浪費服務器內存

jwt優勢json

  • jwt是不基於狀態的,不須要每次請求都帶上token,節約流量
  • 服務器不須要佔用內存,信息相對於可靠些
  • 能夠跨服務端,能夠共用

這都是業界對jwt的評價,但是jwt真的是這樣的嗎?

咱們先來看看JWT的是怎麼生成的?JWT是一種規範.他由下面的一種結構構造而成.跨域

header.payload.signature
複製代碼

JWT 的 Header 部分包含有關如何計算 JWT 簽名的信息,是一個如下形式的 JSON 對象:瀏覽器

{
    "typ": "JWT",
    "alg": "HS256"
}
複製代碼

在上面的 JSON 中,「typ」鍵的值指定對象是JWT,「alg」鍵的值指定用於建立 JWT 簽名的算法。 在示例中,咱們使用 HMAC-SHA256算法(一種使用密鑰的散列算法)來計算簽名(在步驟3中會更詳細的介紹)。安全

建立 PAYLOADbash

JWT 的 payload 部分時是存儲在 JWT 內的數據。在咱們的示例中,身份驗證服務器建立一個JWT,其中存儲有用戶信息,特別是用戶ID。服務器

{
    "userId": "b08f86af-35da-48f2-8fab-cef3904660bd"
}
複製代碼

在咱們的示例中,咱們只將一個聲明放入 payload 中。 你能夠根據須要添加任意數量的聲明。JWT 規定了7個官方字段,供選用。cookie

iss (issuer):簽發人
exp (expiration time):過時時間
sub (subject):主題
aud (audience):受衆
nbf (Not Before):生效時間
iat (Issued At):簽發時間
jti (JWT ID):編號
複製代碼

建立 SIGNATURE網絡

// signature algorithm
data = base64urlEncode( header ) + 「.」 + base64urlEncode( payload )
hashedData = hash( data, secret )
signature = base64urlEncode( hashedData )
複製代碼

是的JWT是經過不斷的計算來進行校驗的.

這裏的性能問題, 指的是該結構帶來的請求數據變多的問題. 在jwt的使用場景中, 全部的請求都須要完整帶上jwt的數據. 因爲payload這部分的數據僅僅是base64後的數據, 並無作任何處理. 因此, 若是在payload中增長過多的數據, 就會致使jwt的結構變大, 從而致使請求的效率下降.

若是把token存在redie或者mongodb中也是一個不錯的選擇. 咱們該如何作呢?

下面我以Laravel

遷移文件以下

$table->bigIncrements('id');
            $table->integer('user_id');
            $table->string('token', 191)->default('')->comment('token');
            $table->integer('expiry_time')->default(0)->comment('到期時間');
            $table->string('ua')->default('')->comment('瀏覽器');
            $table->string('ip')->default('')->comment('使用者ip');
            $table->timestamps();
複製代碼

在經過登陸校驗成功的時候生成Token

$token = md5(uniqid(md5(microtime(true)), true));
        $token = sha1($token);

        UserTokens::create([
            'user_id' => $user->id,
            'token' => $token,
            'ip' => request()->ip(),
            'expiry_time' => time() + 2 * 60 * 60,
            'ua' => request()->userAgent()
        ]);

        return $token;
複製代碼

在須要的路由注入中間件攔截器

class Authenticate extends Controller
{
    public function handle(Request $request, \Closure $next)
    {
        $Authorization = $request->header('Authorization');

        if (!$Authorization) {
            return response($this->error('請登陸', 40001));
        }

        $token = explode(' ', $Authorization);
        $token = $token[1];

        if ($this->validateToken($token)) {
            return $this->validateToken($token);
        }

        return $next($request);
    }

    protected function validateToken($token)
    {
        $dbToken = UserTokens::where('token', $token)->first();
        if ($dbToken->token != $token) {
            return response($this->error('您的信息有誤!', 40010));
        } else if ($dbToken->expiry_time < time()) {
            return response($this->error('token有效期到期', 40020));
        } else if ($dbToken->ua != \request()->userAgent()) {
            return response($this->error('您的信息有誤!', 40010));
        } else if ($dbToken->ip != \request()->ip()) {
            return response($this->error('您的信息有誤!', 40010));
        } else {
            return false;
        }
    }
}
複製代碼

這種方式也是能夠的.

相關文章
相關標籤/搜索