序文
HTTP プロトコル自体はステートレス プロトコルです。
ステートレス: 同じクライアントからの複数のリクエストの場合、サーバーはクライアントのアイデンティティを識別できません.たとえば、クライアントのリクエストを2回目に受信した場合、クライアントが以前にリクエストを送信したかどうかはわかりません.2回目は言うまでもありません.このクライアント要求を処理するときに生成される 1 つのデータ
開発実務では、クライアントの身元を明らかにする必要があるため、技術的な観点からは、Session と Token を使用して HTTP プロトコルのステートレス問題を解決できます。
1. セッションとは?
1 はじめに
セッション: セッション
セッションの本質は MAP 構造のデータです. クライアントが初めてサーバーにリクエストを送信すると, サーバーはクライアントにセッション ID で応答します. 以降の訪問では, クライアントは自動的にセッション ID を持ちます.同時に、各クライアントが以前に保存された独自のデータにアクセスできるように、サーバーのメモリ内に各セッション ID に対応するセッション データが存在します。
セッションはサーバー側のメモリ内のデータであるため、デフォルトでは分散システムはもちろん、クラスタ システムには適していません。
2.使い方
以下は、実際のビジネスに置き換えて、その使用方法を示します。
a. ユーザーのログイン要求を処理するビジネスでは、ログインが正常に検証されると、Session オブジェクトの setAttribute() メソッドが呼び出され、正常にログインしたユーザー オブジェクトがセッション オブジェクトに保存されます。
@RequestMapping("/login")
public int login(@RequestBody User user, HttpSession session, HttpServletResponse response){
System.out.println("user = " + user);
User u = mapper.selectByUsername(user.getUsername());
if(u!=null){
if(u.getPassword().equals(user.getPassword())){
//把登录成功的用户对象保存到会话对象里面
session.setAttribute("user",u);
return 1;
}
return 2;
}
return 3;
}
b. Session オブジェクトの getAttribute() メソッドを呼び出して、セッション オブジェクトを取り出します。
@RequestMapping("/currentUser")
public User currentUser(HttpSession session){
//取出会话对象中 登录成功时保存进去的用户对象
User user = (User)session.getAttribute("user");
System.out.println("user = " + user);
return user;
}
c. クライアントがログアウトしたら、Session オブジェクトの removeAttribute() メソッドを呼び出して、セッション オブジェクトを削除します。
@RequestMapping("/logout")
public void logout(HttpSession session){
//删除会话对象中的user
session.removeAttribute("user");
}
2.トークンとは?
1 はじめに
トークン: チケット、トークン
ユーザーがログインしようとすると、リクエストがサーバーに送信されます。サーバー側の認証が成功すると、トークン データが生成され、クライアントに応答します。このトークンは意味のあるデータです。クライアントは、後続の各リクエストにトークンを送信する必要があります。 . このトークン データを運ぶと、サーバーはトークンを解析してユーザー ID を識別します。
2.使い方
JWT: JSON Web Token: JSON 形式を使用して複数のデータを表すトークン
JWT を使用する前に、JWT を生成し、JWT を解析するために、関連する依存関係をプロジェクトに追加する必要があります。公式 Web サイト jwt.io を参照してください。
例えば:
<!-- JJWT(Java JWT) -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
生の JWT データには以下が含まれている必要があります。
HEADER: ALGORITHM & TOKEN TYPE (アルゴリズムとトークンタイプ)
ペイロード (ロード): データ
VERIFY SIGNATURE (署名の検証)
以下は、テストクラスでそれを使用する方法を示しています。
public class JwtTests {
// Secret Key
String secretKey = "97iuFDVDfv97iuk534Tht3KJR89kBGFSBgfds";
@Test
public void testGenerate() {//生成JWT
// 准备Claims值
Map<String, Object> claims = new HashMap<>();
claims.put("id", 9527);
claims.put("name", "liudehua");
claims.put("nickname", "andy");
// JWT的过期时间
Date expiration = new Date(System.currentTimeMillis() + 5 * 60 * 1000);
//五分钟后过期
System.out.println("过期时间:" + expiration);
// JWT的组成:Header(头:算法和Token类型)、Payload(载荷)、Signature(签名)
String jwt = Jwts.builder()
// Header
.setHeaderParam("alg", "HS256")
.setHeaderParam("typ", "JWT")
// Payload
.setClaims(claims)
.setExpiration(expiration)
// Signature
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
System.out.println("JWT=" + jwt);
/*eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoibGl1ZGVodWEiLCJuaW
NrbmFtZSI6ImFuZHkiLCJpZCI6OTUyNywiZXhwIjoxNjYyNDYzMzcyfQ.GW6aDBTc5ZZh
PbsaqPeP3MNaMN2e6jjlzX_VZdqtwR8*/
}
@Test
public void testParse() {//解析JWT
// 注意:必须使用相同secretKey生成的JWT,否则会解析失败
// 注意:不可以使用过期的JWT,否则会解析失败
// 注意: 使用过期的JWT,也会解析失败
// 注意:复制粘贴此JWT时,不要带“尾巴”,否则会解析失败
// 注意:不可以恶意修改JWT中的任何字符,否则会解析失败
String jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoibGl1ZGVodW" +
"EiLCJuaWNrbmFtZSI6ImFuZHkiLCJpZCI6OTUyNywiZXhwIjoxNjYyNDYzMzcyfQ" +
".GW6aDBTc5ZZhPbsaqPeP3MNaMN2e6jjlzX_VZdqtwR8";
Claims claims = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(jwt)
.getBody();
Integer id = claims.get("id", Integer.class);
String name = claims.get("name", String.class);
String nickname = claims.get("nickname", String.class);
System.out.println("id = " + id);
System.out.println("name = " + name);
System.out.println("nickname = " + nickname);
}
}
要約する
セッションとトークンについて: セッションは、デフォルトでサーバーのメモリに保存されるデータであり、特定のサーバー メモリ リソースを占有し、クラスターや分散システムには適していません (ただし、セッションを共有することで解決できます)。トークンの本質は、意味のあるデータを暗号化した結果であり、各サーバーは、暗号化されたデータを解析する機能のみを備えていればよいということです。理論的に取得できる情報の 1 つはメモリ リソースを占有せず、クラスタや分散システムに適していますが、一定の暗号解読のリスクがあります (確率は非常に低い)。