1. 程式人生 > >JSON Web Tokens的實現原理

JSON Web Tokens的實現原理

前言

最近在做一個python專案的改造,將python專案重構為java專案,過程中遇到了這個知識點,覺得這個蠻實用的,所以下班後回來趁熱打鐵寫下這篇總結,希望後面的人能夠有所借鑑,少走彎路。

一、優勢簡介

JSON Web Tokens簡稱jwt,是rest介面的一種安全策略。本身有很多的優勢:

  1. 解決跨域問題:這種基於Token的訪問策略可以克服cookies的跨域問題。
  2. 服務端無狀態可以橫向擴充套件,Token可完成認證,無需儲存Session。
  3. 系統解耦,Token攜帶所有的使用者資訊,無需繫結一個特定的認證方案,只需要知道加密的方法和金鑰就可以進行加密解密,有利於解耦。
  4. 防止跨站點指令碼攻擊,沒有cookie技術,無需考慮跨站請求的安全問題。

二、原理簡介

JSON Web Tokens的格式組成,jwt是一段被base64編碼過的字元序列,用點號分隔,一共由三部分組成,頭部header,訊息體playload和簽名sign。

1.jwt的頭部Header是json格式:

{
    "typ":"JWT",
    "alg":"HS256",
    "exp":1491066992916
}

其中typ是type的簡寫,代表該型別是JWT型別,加密方式宣告是HS256,exp代表當前時間.

2.jwt的訊息體Playload

{
    "userid":"123456",
    "iss":"companyName"
}

訊息體的具體欄位可根據業務需要自行定義和新增,只需在解密的時候注意拿欄位的key值獲取value。

3.簽名sign的生成

最後是簽名,簽名的生成是把header和playload分別使用base64url編碼,接著用’.‘把兩個編碼後的字串連線起來,再把這拼接起來的字串配合金鑰進行HMAC SHA-256演算法加密,最後再次base64編碼下,這就拿到了簽名sign. 最後把header和playload和sign用’.‘ 連線起來就生成了整個JWT。

三、校驗簡介

整個jwt的結構是由header.playload.sign連線組成,只有sign是用金鑰加密的,而所有的資訊都在header和playload中可以直接獲取,sign的作用只是校驗header和playload的資訊是否被篡改過,所以jwt不能保護資料,但以上的特性可以很好的應用在許可權認證上。

1.加密

比如要加密驗證的是userid欄位,首先按前面的格式組裝json訊息頭header和訊息體playload,按header.playload組成字串,再根據金鑰和HS256加密header.playload得到sign簽名,最後得到jwtToken為header.playload.sign,在http請求中的url帶上引數想後端服務請求認證。

2. 解密

後端服務校驗jwtToken是否有權訪問介面服務,進行解密認證,如校驗訪問者的userid,首先
用將字串按.號切分三段字串,分別得到header和playload和sign。然後將header.playload拼裝用金鑰和HAMC SHA-256演算法進行加密然後得到新的字串和sign進行比對,如果一樣就代表資料沒有被篡改,然後從頭部取出exp對存活期進行判斷,如果超過了存活期就返回空字串,如果在存活期內返回userid的值。

四、程式碼示例

1.python程式碼的加密解密

#!/usr/bin/env python
# coding: utf-8

from itsdangerous import BadTimeSignature, SignatureExpired
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer

APP_SECRET_KEY="secret"
MAX_TOKEN_AGE=1800
token_generator = Serializer(APP_SECRET_KEY, expires_in=MAX_TOKEN_AGE)

def generate_auth_token(userid):
    access_token = token_generator.dumps({"userid":userid})
    return access_token

def verify_token(token):
    try:
        user_auth = token_generator.loads(token)
        print type(token_generator)
    except SignatureExpired as e:
        raise e
    except BadTimeSignature as e:
        raise e
    return user_auth

2. java程式碼的加密解密

package api.test.util;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;

/**
 * jwt加解密實現
 * 
 * @author zhengsc
 */
@Slf4j
public class TokenUtil {

    private String ISSUER = "companyName"; // 機構

    private String APP_SECRET_KEY = "secret"; // 金鑰

    private long MAX_TOKEN_AGE = 1800; // 存活期

    /**
     * 生成userId的accessToken
     * 
     * @param userid
     * @return
     */
    public String generateAccessToken(String userid) {
        JSONObject claims = new JSONObject();
        claims.put("iss", ISSUER);
        claims.put("userid", userid);
        String accessToken = sign(claims, APP_SECRET_KEY);
        return accessToken;
    }

    /**
     * 解密程式返回userid
     * 
     * @param token
     * @return
     */
    public String verifyToken(String token) {
        String userid = "";
        try {
            String[] splitStr = token.split("\\.");
            String headerAndClaimsStr = splitStr[0] + "." +splitStr[1];
            String veryStr = signHmac256(headerAndClaimsStr, APP_SECRET_KEY);
            // 校驗資料是否被篡改
            if (veryStr.equals(splitStr[2])) {
                String header = new String(Base64.decodeBase64(splitStr[0]),"UTF-8");
                JSONObject head = JSONObject.fromObject(header);
                long expire = head.getLong("exp") * 1000L;
                long currentTime = System.currentTimeMillis();
                if (currentTime <= expire){ // 驗證accessToken的有效期
                    String claims = new String(Base64.decodeBase64(splitStr[1]),"UTF-8");
                    JSONObject claim = JSONObject.fromObject(claims);
                    userid = (String) claim.get("userid");
                }
            }
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage(), e);
        }

        return userid;
    }

    /**
     * 組裝加密結果jwt返回
     * 
     * @param claims
     * @param appSecretKey
     * @return
     */
    private String sign(JSONObject claims, String appSecretKey) {
        String headerAndClaimsStr = getHeaderAndClaimsStr(claims);
        String signed256 = signHmac256(headerAndClaimsStr, appSecretKey);
        return headerAndClaimsStr + "." + signed256;
    }

    /**
     * 拼接請求頭和宣告
     * 
     * @param claims
     * @return
     */
    private String getHeaderAndClaimsStr(JSONObject claims) {
        JSONObject header = new JSONObject();
        header.put("alg", "HS256");
        header.put("typ", "JWT");
        header.put("exp", System.currentTimeMillis() + MAX_TOKEN_AGE * 1000L);
        String headerStr = header.toString();
        String claimsStr = claims.toString();
        String headerAndClaimsStr = Base64.encodeBase64URLSafeString(headerStr.getBytes()) + "."
                + Base64.encodeBase64URLSafeString(claimsStr.getBytes());
        return headerAndClaimsStr;
    }

    /**
     * 將headerAndClaimsStr用SHA1加密獲取sign
     * 
     * @param headerAndClaimsStr
     * @param appSecretKey
     * @return
     */
    private String signHmac256(String headerAndClaimsStr, String appSecretKey) {
        SecretKey key = new SecretKeySpec(appSecretKey.getBytes(), "HmacSHA256");
        String result = null;
        try {
            Mac mac;
            mac = Mac.getInstance(key.getAlgorithm());
            mac.init(key);
            result = Base64.encodeBase64URLSafeString(mac.doFinal(headerAndClaimsStr.getBytes()));
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            log.error(e.getMessage(), e);
        }
        return result;
    }

}

相關推薦

JSON Web Tokens實現原理

前言 最近在做一個python專案的改造,將python專案重構為java專案,過程中遇到了這個知識點,覺得這個蠻實用的,所以下班後回來趁熱打鐵寫下這篇總結,希望後面的人能夠有所借鑑,少走彎路。 一、優勢簡介 JSON Web Tokens簡稱jwt,

JSON Web Tokens(JWT)

header xiaomi 含義 安全 glog format creation json hash 現在API越來越流行,如何安全保護這些API? JSON Web Tokens(JWT)能提供基於JSON格式的安全認證。它有以下特點: JWT是跨不同語言的,JWT可以

JWT(JSON WEB TOKENS)-一種無狀態的認證機制

轉載自:http://www.tuicool.com/articles/R7Rj6r3 JWT(JSON Web Tokens ) ———— 一種無狀態的認證機制 一、什麼是JWT? JWT是一種用於雙方之間傳遞安全資訊的簡潔的、URL安全的表述性宣告規範。JWT作

Authentication For Your React and Express Application w/ JSON Web Tokens

BackendUser ModelTo get started we need to create a MongoDB/Mongoose model for a User object. Here is an example of one that I created:// User.jsconst mong

5 Easy Steps to Understanding JSON Web Tokens (JWT)

5 Easy Steps to Understanding JSON Web Tokens (JWT)In this article, the fundamentals of what JSON Web Tokens (JWT) are, and why they are used will be expla

Python REST API Authentication with JSON Web Tokens

1. Setting up the API Client ModelAdd a new files models/client.py and add the code below. This model will store an API clients access credentials. The cli

Windows 下Maven+Tomcat 8 使用JAVA以及 Json Web Token 實現 單點登入demo

0.準備工作 如果你本地環境都OK,可以跳過。 1.簡介 json web token(JWT)是一種新的使用者認證方式,不同與以前的Session. JWT不需要伺服器端儲存使用者資訊,當用戶登入後,伺服器將使用者資訊放入加密放入t

微服務架構中的身份驗證問題 :JSON Web Tokens( JWT)

場景介紹 軟體安全是一件很負責的問題,由於微服務系統中每個服務都要處理安全問題,所以在微服務場景下會更加複雜,一般我們會四種面向微服務系統的身份驗證方案。 在傳統的單體架構中,單個服務儲存所有的使用者資料,可以校驗使用者,並在認證成功後建立HTTP會

介面的安全控制 (JWT) JSON Web Tokens

前言 如果你的介面是開放的,誰都可以成功呼叫,那麼會非常危險。因此除非你真的想做開放式服務,否則要對使用者的請求做許可權控制 舉例:假如我想自己寫一個“張三版新浪微博”的APP。 新浪微博開放了微博的介面,所有人可以呼叫這些介面“發微博”、“看微博”等。當然不是隨便呼叫,而

JWT(JSON Web Tokens)的使用

由來 做了這麼長時間的web開發,從JAVA EE中的jsf,spring,hibernate框架,到spring web MVC,到用php框架thinkPHP,到現在的nodejs,我自己的看法是越來越喜歡乾淨整潔的web層,之前用jsf開發做view層的時候,用的

Java web server 基本實現原理

tro 主線程 inpu 請求報文 永遠 原理 args ket io阻塞 public class WebServer { //服務端Socket只要一個,所以定義成static, 同一時間只能一個線程訪問(主線程) private static Se

Python Web開發中,WSGI協議的作用和實現原理詳解

首先理解下面三個概念: WSGI:全稱是Web Server Gateway Interface,WSGI不是伺服器,python模組,框架,API或者任何軟體,只是一種規範,描述web server如何與web application通訊的規範。 uwsgi:與WSGI一樣是一種協議,是uWSGI伺服器

java web自動登入原理實現

1、建立web工程2、建立使用者名稱、密碼的資料庫並建立對應的連線工廠及dao,service3、建立登入頁面(表單),含有記住密碼選項4、建立Servlet,接收登入引數,查詢資料庫,登入判斷,進行成功跳轉(歡迎頁面),     a、session記住登入使用者     b

JSON Web Token(JWT)原理和用法介紹

JSON Web Token(JWT)是目前最流行的跨域身份驗證解決方案。今天給大家介紹一下JWT的原理和用法。 一、跨域身份驗證 Internet服務無法與使用者身份驗證分開。一般過程如下。 1. 使用者向伺服器傳送使用者名稱和密碼。 2. 驗證伺服器後,相關資料(如使用者角色,登入時間等)將儲存在

Python實現JWT(JSON Web Token)認證

作者介紹 張龍(zero),一線運維老鳥。致力於LINUX/PYTHON/開源技術研究。 常見認證方法 首先要明白,認證和授權是不同的。認證是判定使用者的合法性,授權是判定使用者的許可權級別是否可執行後續操作。這裡所講的僅含認證。 basic認證 這是http協議中所帶帶基本認證,是一

JSON Web Token(JWT)使用步驟說明 JSON Web Token(JWT)原理和用法介紹

在JSON Web Token(JWT)原理和用法介紹中,我們瞭解了JSON Web Token的原理和用法的基本介紹。本文我們著重講一下其使用的步驟: 一、JWT基本使用 Gradle下依賴 : compile 'com.auth0:java-jwt:3.4.0' 示例介紹: im

基於.net搭建熱插拔式web框架(實現原理

第一節:我們為什麼需要一個熱插拔式的web框架? 模組之間獨立開發 假設我們要做一個後臺管理系統,其中包括“使用者活躍度”、“產品管理”、"賬單管理"等模組。每個模組中有自己的業務特性,這些模組都與具體業務高度耦合,很難由一個團隊開發完所有模組。這樣看來,由資料事業部的同事來開發“使用者活躍度”模

android客戶端+JAVA WEB伺服器實現json資料解析

import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.But

Spring Boot實戰之Filter實現使用JWT進行介面認證 jwt(json web token) 使用者傳送按照約定,向服務端傳送 Header、Payload 和 Signature,

Spring Boot實戰之Filter實現使用JWT進行介面認證 jwt(json web token) 使用者傳送按照約定,向服務端傳送 Header、Payload 和 Signature,幷包含認證資訊(密碼),驗證通過後服務端返回一個token,之後使用者使用該

網路程式設計(一)——淺析web伺服器與瀏覽器的實現原理

我們基本每天都在通過WEB瀏覽器,去瀏覽一些新聞,看看視訊之類的。眾所周知,這就是所謂的B/S結構(Browser/Server,瀏覽器/伺服器模式),是WEB興起後的一種網路結構模式,WEB瀏覽器是客戶端最主要的應用軟體。那順道就來簡單的看一下,所謂的Web伺服器(例如知名