表示する前のヒント:
この記事で使用されているIDEAバージョンは究極の2019.1であり、JDKバージョンは1.8.0_141です。
1はじめに
コンピュータID認証では、トークン(一時的)を意味します。実際、トークンの方が一般的であり、シークレットコードと呼ぶことができます。データ送信の前に、シークレットコードを最初にチェックする必要があります。さまざまなデータ操作に対してさまざまなシークレットコードが許可されます。
2.JWT
JSON Webトークン、JSON Webトークン、次の例もJWTによって実装されたトークン認証に基づいています。以下は、完成したJWT文字列です。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODMyOTQxNzEsInVzZXJOYW1lIjoidXNlciIsInBhc3N3b3JkIjoiMTExMTExMTEifQ.t6JLktclylpt2s5T_B1KDxYCJALr-fbZsy1J_YT57Jk
ヘッダー、ペイロード、署名の3つの部分で構成されています
2.1ヘッダー
2つの部分で構成されます
-
宣言タイプはJWTです。
-
暗号化アルゴリズムを宣言し、HMACSHA256を使用します
以下に示すように、JWTヘッダー部分はJSONオブジェクトです。
{
'typ': 'JWT',
'alg': 'HS256'
}
Base64で暗号化すると、JWTが最初の部分を構成します。
2.2ペイロード
ペイロード部分はJWTのメインコンテンツ部分であり、3つの部分で構成されるJSONオブジェクトでもあります。
-
標準に登録された宣言
-
公式声明
-
プライベートステートメント
標準に登録されている宣言には、7つのデフォルトフィールドがあります。
-
iss:発行者
-
exp:有効期限
-
サブ:件名
-
aud:ユーザー
-
nbf:以前は利用できません
-
iat:リリース時間
-
jti:JWTIDはJWTを識別するために使用されます
公式声明
公式声明では、あらゆる情報を追加できます。通常、ユーザー関連情報やビジネスに必要なその他の必要な情報を追加します(機密情報は推奨されません)。
プライベートステートメント
プライベートステートメントは、プロバイダーとコンシューマーが共同で定義するステートメントです(機密情報は推奨されません)。
次の例はサンプルペイロードです
{
"sub": "1234567890",
"name": "userName",
"admin": true
}
Base64で暗号化して、JWTの2番目の部分を形成します。
注:JWTはデフォルトで暗号化されておらず、誰でもその内容を解釈できます。したがって、情報漏えいを防ぐために、個人情報フィールドを作成したり、機密情報を保存したりしないでください。
2.3署名
署名ハッシュ部分は、データの上記2つの部分に署名し、指定されたアルゴリズムを使用してハッシュを生成し、データが改ざんされないようにします。これは3つの部分で構成されています。
-
ヘッダー(Base64で暗号化)
-
ペイロード(Base64暗号化)
-
秘密
サーバーには秘密鍵が必要です。秘密鍵はサーバーにのみ保存され、ユーザーに開示することはできません。次に、ヘッダーで指定された署名アルゴリズム(デフォルトではHMAC SHA256)を使用して、次の式に従って署名を生成します。
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
署名ハッシュが計算された後、JWTヘッダー、ペイロード、および署名ハッシュの3つの部分が結合されて文字列になり、各部分が「。」で区切られてJWTオブジェクト全体が形成されます。
3.使用する
クライアントは、サーバーから返されたJWTを受信し、CookieまたはlocalStorageに保存します。
その後、クライアントはサーバーと対話するときにJWTをもたらします。Cookieに保存されている場合は、自動的に送信できますが、ドメインをまたがることはないため、通常、HTTPリクエストのHeaderAuthorizationフィールドに入力されます。
次の形式を使用します
Authorization: Bearer JWT
JWTインタラクションのプロセス全体を次の図に示します。
4.例
この例では、JWT署名と検証を実装するためのJavaのみを提供しており、http送信の使用は後で追加されます。
pom.xmlが参照する必要があるjarパッケージ
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.10.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.10.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.10.2</version>
</dependency>
ツールクラスTokenUtil.java
package token;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class TokenUtil {
//token过期时长30分钟
private static final long EXPIRE_TIME = 30 * 60 * 1000;
//token私钥
private static final String TOKEN_SECRET = "abcdefg";
public static String sign(String userName, String password) {
String signData = "";
//过期时间
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
//私钥及加密算法
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
//设置头信息
Map<String, Object> header = new HashMap();
header.put("typ", "JWT");
header.put("alg", "HS256");
signData = JWT.create()
.withHeader(header)
.withClaim("userName", userName)
.withClaim("password", password)
.withExpiresAt(date)
.sign(algorithm);
return signData;
}
/**
* @Description token解码校验
* @param token
* @return
* @Create 2020-03-03 by jjy
*/
public static boolean verfiy(String token) {
try {
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
JWTVerifier jwtVerifier = JWT.require(algorithm).build();
DecodedJWT decodedJWT = jwtVerifier.verify(token);
String userName = decodedJWT.getClaim("userName").asString();
String password = decodedJWT.getClaim("password").asString();
if(!Test.USERNAME.equals(userName) || !Test.PASSWORD.equals(password)) {
return false;
}
if(new Date().getTime() > decodedJWT.getExpiresAt().getTime()){
return false;
}
} catch (Exception e) {
return false;
}
return true;
}
}
テストクラスTest.java
package token;
public class Test {
public static final String USERNAME = "user";
public static final String PASSWORD = "11111111";
public static void main(String[] args) {
String token = TokenUtil.sign(USERNAME, PASSWORD);
System.out.println("加密后的token为:" + token);
boolean flag = TokenUtil.verfiy(token);
if(flag){
System.out.println("校验成功");
} else {
System.out.println("校验失败");
}
}
}
結果は以下のとおりです。