1.JWT公式サイト紹介
JSONウェブトークンとは何ですか?
JSON Web Token (JWT) は、関係者間で情報を JSON オブジェクトとして安全に送信するためのコンパクトで自己完結型の方法を定義するオープン スタンダード (RFC 7519) です。この情報はデジタル署名されているため、検証および信頼できます。JWTS は、秘密キー (HMAC アルゴリズムを使用)、または RSA または ECDSA を使用した公開/秘密キーのペアを使用して署名できます。JWTS は暗号化できるだけでなく、当事者間の機密性も提供しますが、ここではトークンの署名に焦点を当てます。署名されたトークンは、その中に含まれるクレームの整合性を検証しますが、暗号化されたトークンはそれらのクレームを他の当事者から隠します。公開鍵と秘密鍵のペアを使用してトークンに署名すると、その署名は、秘密鍵を保持している当事者のみが署名した者であることも証明します。
JWT は、端的に言えば、Token を生成するための暗号アルゴリズムであり、Token に情報を格納し、鍵を持っている者だけが Token の正当性を検証することができます。
2. なぜ JWT を使用するのですか?
2.1 従来のセッション認証
HTTP プロトコルはステートレスであるため、サーバーは各リクエストがどのユーザーからのものかを識別できません。
したがって、従来の開発では、ユーザーを認証する場合、大まかに次のような操作が行われます: 1. ユーザーは
クライアントでアカウントのパスワードを入力してログインします。2
. サーバーはアカウントを検証します。認証に成功すると、ユーザー情報はサーバーに保存され、session_id の文字列が生成されてクライアントに返され、Cookie に保存されます
。認証を完了するには、Cookie 内の session_id をサーバーに送信する必要があります。
2.2 セッション認証のデメリット
1. 大量のユーザー情報をサーバーに保存するとサーバーのオーバーヘッドが増加するため、クラスタや分散環境を使用する場合はセッション共有の仕組みも考慮する必要があります。
2. クロスサイトリクエストフォージェリ攻撃(CSRF)のリスクがある
クロスサイト リクエスト フォージェリ: システム A で転送を行った後、危険なシステム B にアクセスするとします。システム B は session_id を転送し、苦労して稼いだお金を盗む可能性があります。サーバーは session_id によってアカウントを識別しますが、session_id が漏洩すると、予期せぬリスクが発生します。
2.3 JWTの登場
JWT の認証メカニズムは HTTP プロトコルに似ており、ステートレスでもあります。ユーザーの非機密情報をトークンに保存できます。各リクエスト中に、情報はヘッダーに含まれてサーバーに送信されます。サーバーはキーを使用して解析するため、ユーザーの関連情報を取得できます。この時点では、 、回避これにより、セッションに保存される過剰な情報が排除され、サーバー側のオーバーヘッドが削減されます。
2.4 JWTの構成
JWT はヘッダー、ペイロード、署名の 3 つの部分で構成されており、
JWT はすべて次のようになります: liang.zai.bo
liang はヘッダー、zai はペイロード、bo は署名を表します。
ヘッダー: ヘッダーは、タイプや署名アルゴリズムなど、Json Web Token の基本情報を記述するために使用されます。次の JSON 形式の文字列を Base64 エンコードしてヘッダーを取得します。
{
"alg":"HS256",
"typ":"JWT"
}
ペイロード: ペイロードは、いくつかの非機密情報を保存する JWT のメイン コンテンツ部分です。公式 Web サイトでは次の 5 つのフィールドが定義されています: iss、sub、aud、exp、iat
iss: JWT の発行者
sub: メインJWT の一部
aud: JWT を受信する側
exp: Unix タイムスタンプ形式の JWT の有効期限 (必ず注意してください! そうしないとトラップになります) iat: JWT Base64 エンコード
の発行時刻
次の JSON 文字列を使用してペイロードを取得します。
{
"sub":"liangzaibo",
"exp":"666666666666666666666",
"username":"liangzaibo",// 我们还可以自定义字段
}
署名: Base64 でヘッダーとペイロードをエンコードし、ヘッダーで指定された署名アルゴリズム、つまり HS256(Base64Encode(Header) + “.” + Base64Encode(Payload), SECRET) を使用して提供されたキーを暗号化します。
2.5 JWT の実践
public class Main {
public static void main(String[] args) throws ParseException {
// header 可有可无,此处为了方便演示,默认为{"alg":"HS256"}
Map<String, Object> header = new HashMap<String, Object>();
header.put("alg", "HS256");
header.put("typ", "JWT");
// claims代表Payload的主要内容,可以自定义字段
Map<String, Object> cliams = new HashMap<String, Object>();
cliams.put("username", "liangzaibo");
String token = generateJwtToken(header, cliams);
System.out.println(token);
//eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.
//eyJleHAiOjE2MTAyMDgwMDAsImlhdCI6MTYwOTQ5ODk3OSwidXNlcm5hbWUiOiJsaWFuZ3phaWJvIn0.
//vglPuCoRdTQbVq68TykiDsiev-p_Rr61WQvJHwqOLWM
Claims claims = parseJwtToken(token);
System.out.println(claims);
// {exp=1610208000, iat=1609498979, username=liangzaibo}
}
/**
* 生成JWT令牌
*/
public static String generateJwtToken(Map<String,Object> header, Map<String,Object> claims) throws ParseException {
return Jwts.builder()
.setHeader(header)
.setClaims(claims)
.signWith(SignatureAlgorithm.HS256, "SECRET") //加密算法以及密钥
.setExpiration(new SimpleDateFormat("yyyy-MM-dd").parse("2021-01-10")) // JWT过期时间
.setIssuedAt(new Date()) // 签发时间
.compact();
}
/**
* 解析JWT
*/
public static Claims parseJwtToken(String token){
return Jwts.parser()
.setSigningKey("SECRET")
.parseClaimsJws(token)
.getBody();
}
2.6 注意事項
- 機密情報を JWT に保存してはなりません。ヘッダーとペイロードは 1 回だけ Base64 エンコードされるため、ヘッダーとペイロードが 1 回 Base64 デコードされる限り、内部情報を取得できます。
- JWT はクロスランゲージをサポートしていますが、開発者が JWT の有効期限をタイムスタンプ形式ではなく設定しているプロジェクトに遭遇しました。その結果、最終的に同期解析を実行できなくなりました。したがって、保存された JWT の exp 有効期限はタイムスタンプである必要があることに注意する必要があります。そうしないと、最終的に解析されません。
- JWT を生成する場合、有効期限を長すぎるように設定するのは簡単ではありません。JWT は一度発行されると取り消すことができず、無効になるまで有効期限に達するまで待つ必要があるためです。
- JWT はあらゆる場面に適しているわけではありませんが、ビジネスで暗号化と復号化が必要ない場合、JWT を使用するのは負担です。