前回の記事では、Cookieやその他のセッション関連の概念を詳しく紹介しましたが、Cookieはセッション情報をクライアントに保存するための手法であり、その外観はプログラマーの作業を大幅に簡素化します。Cookieはシンプルで便利で実用的なクライアントセッションテクノロジーであり、その重要性は自明です。本日は、Cookieのいくつかのアプリケーションシナリオについて説明します。
Cookieと呼ばれる中国語に翻訳されたCookieは、小さなCookieと呼ばれますが、これは非常に適切です。上記のように、小さなCookieごとに異なるパターンがあり、小さな重要な情報の保存を示します。
1.パスワードを記憶する簡単な実装
QQなど、誰もが経験しなければならないパスワード機能を覚えておいてください。一度パスワードを入力した後は、長い間パスワードを再入力する必要はありません。それがどのように実装されるべきか見てみましょう。
作業のこの部分は主にフロントエンドにあります。フロントエンドのコードを以下に示します。最初はLogin.jspです。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="./js/jquery.cookie.js"></script>
<script src="./js/login.js"></script>
<title>Insert title here</title>
</head>
<body>
<form id="loginForm" action="xxx" method="post">
<input id="username" name="username" type="text"/>
<br />
<input id="password" name="password" type="password" />
<br />
<!-- form提交前存储Cookie -->
<button type="button" οnclick="loginSubmit()">提交</button>
</form>
</body>
</html>
jquery.cookie.jsのダウンロードリンクは次のとおりです。https://github.com/carhartl/jquery-cookie/tree/master/src
login.jsのコードは次のとおりです。これは、loginSubmitメソッドとページ初期化アクションを定義します。
//页面DOM加载完毕后执行
//如果本地存储了账号、密码,则将其填充到输入框中
$(document).ready(function(){
const cookieName = $.cookie('loginName');
const cookiePwd = $.cookie('loginPwd');
console.log(cookieName + "," + cookiePwd);
if(cookieName != '' && cookieName != null){
$("#username").val(cookieName);
}
if(cookiePwd != '' && cookiePwd != null){
$("#password").val(cookiePwd);
}
})
//登录
function loginSubmit(){
console.log("执行了js中的方法");
//将账号名和密码存入Cookie中
const userName = $("#username").val();
$.cookie('loginName', userName);
const password = $("#password").val();
$.cookie('loginPwd', password);
//阻断form表单提交,测试时使用
//return false;
$("#loginForm").submit();
}
ここでは、テストのスクリーンショットは提供しません。コードが提供されているので、自分でテストできます。パスワードを記憶する機能は、ログインを自動的に入力するという明らかな機能にすぎません。ここでは、Cookieが設定されているため、リクエストごとにアカウントのパスワード情報が自動的に送信されるため、バックエンドにインターセプターを追加できます。有効期限が切れた場合は、パスワードの検証後に新しいパスワードを作成することもできるため、再度ログインする必要はありません。
2.トークンを使用してセキュリティを強化する
上記の例では、ブラウザー側でパスワードをクリアテキストで保存しましたが、ブラウザーはパスワードを暗号化して保存しますが、ネットワーク転送では、パスワードはクリアテキストで転送されるため、セキュリティ下がる。この問題を解決するために、一般に、保存する際にクライアントに碑文パスワードを直接保存するのではなく、暗号化技術を介してクライアントにトークンを保存します。
トークンはトークンとして理解できます。上記のパスワードを覚えておいてください。ユーザーが正常にログインした後、暗号化してパスワードなどの個人情報を暗号化し、暗号化された文字列を取得して顧客に保存できます。最後に、必要に応じて(セッションの期限切れなど)次回待機し、プレーンテキストアカウントのパスワードを直接使用するのではなく、トークンの有効性を直接確認します。
安全性と単純さのために、暗号化にはMD5を使用します(ここでは対称暗号化アルゴリズムAESをお勧めします)。また、ユーザー名とパスワードが正しいことを確認した後、暗号化作業をバックエンドに配置しました。
ここでは、LoginServletのdoGetメソッドのコードを見てみましょう。
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=utf-8");
String userName = request.getParameter("username");
String password = request.getParameter("password");
UserService userService = UserService.getInstance();
try {
String result = userService.loginByNameAndPassword(userName, password);
boolean isSuccess = false;
// 登录成功
if ("Success".equals(result)) {
isSuccess = true;
// 创建Session
HttpSession session = request.getSession();
// 生成一个token,当Session过期时,可以通过此token来验证是否登录过
// 规则,userName-password 的md5值
String token = MD5Util.encodeByMD5(userName + "-" + password);
Cookie loginCookie = new Cookie("loginToken", token);
Cookie nameCookie = new Cookie("userName", userName);
// 将Cookie添加到response中
response.addCookie(loginCookie);
response.addCookie(nameCookie);
} else {
// 登录失败
System.out.println("登录失败的原因为:" + result);
// 跳转登录失败页面
// response.sendRedirect("/FirstProject/index.jsp");
}
// 输出页面
// ...
}
前記実施部分は省略し、サービス参照することができる上記。上記の例では、ユーザー名とパスワードを連結して暗号化していますが、MD5暗号化は復号化できないため、ユーザー名を保存するCookieも作成します。次回トークン情報を確認する必要がある場合は、CookieのloginNameに基づいてデータベースのパスワードを照会し、スプライス後にMD5暗号化値を計算して、トークンと比較するだけです。簡単なサンプルコードは次のとおりです。
/**
* 根据登录名校验token是否正确
*
* @param loginName
* @param loginToekn
* @return true || false
* @throws ClassNotFoundException
* @throws SQLException
*/
public boolean checkToken(String loginName, String loginToekn) throws ClassNotFoundException, SQLException {
UserDao userDao = new UserDao();
User user = userDao.findUserByName(loginName);
String password = user.getPassword();
String newToken = MD5Util.encodeByMD5(loginName + "-" + password);
if (newToken.equals(loginToekn)) {
System.out.println("token检验正确");
return true;
}
System.out.println("token检验错误");
return false;
}
MD5Utilのコードは次のとおりです。
package xxx;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Util {
/**
* 对传入的字符串进行MD5加密
*
* @param str
* @return 加密后的字符串
*/
public static String encodeByMD5(String str) {
byte[] bytes = null;
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
bytes = md5.digest(str.getBytes("utf-8"));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return bytesTo16BString(bytes);
}
/**
* 将字节数组转换为16进制格式的字符串
*
* @param bytes
* @return
*/
private static String bytesTo16BString(byte[] bytes) {
StringBuffer res = new StringBuffer();
int num = 0;
for (int i = 0; i < bytes.length; i++) {
num = bytes[i] > 0 ? bytes[i] : 255 + bytes[i];
String hex = Integer.toHexString(num);
res.append(hex.length() < 2 ? 0 + hex : hex);
}
return res.toString();
}
}
3. JWTのアイデアから学ぶ
JWT(JSONウェブトークン)技術は、オープンな業界標準であるRFC 7519の方法、二者間で転送される文に示すためのコンパクト、URLの安全な方法です。JWTの宣言はJSONオブジェクトとしてエンコードされ、JWS(JSON Web Signature)構造のペイロードまたはJWE(JSON Web Encryption)構造のプレーンテキストとして使用されるため、宣言にデジタル署名を付けたり、メッセージ検証コードで整合性を保護できます。 (MAC)および/または暗号化されたメッセージ。
つまり、JWTは機密情報をJSONオブジェクトに入れ、ヘッダー、署名、その他の情報を追加し、オブジェクト全体を文字列に暗号化してクライアントに保存します。この記事では、簡単な手動実装であるJWTの概念についても触れています。
まず、情報を格納するオブジェクトを定義してみましょう(JSONObjectを直接作成することもできます)。コードは次のとおりです。
public class JwtDataPojo {
//登录用户
private String name;
// 其他信息...
//登录时间
private Date loginDate;
// Getter、Setter方法
// ...
}
LoginServletへのログインが成功するようにコードを次のように変更しました。
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//...
UserService userService = UserService.getInstance();
try {
String result = userService.loginByNameAndPassword(userName, password);
boolean isSuccess = false;
// 登录成功
if ("Success".equals(result)) {
isSuccess = true;
JwtDataPojo dataPojo = new JwtDataPojo();
dataPojo.setName(userName);
dataPojo.setLoginDate(new Date());
// 生成加密后的字符串
String jwtToken = AESUtil.encrypt(JSON.toJSONString(dataPojo), "123456");
Cookie cookie = new Cookie("JwtToken", jwtToken);
// 将Cookie添加到response中
response.addCookie(cookie);
} else {
// 登录失败
System.out.println("登录失败的原因为:" + result);
// 跳转登录失败页面
// response.sendRedirect("/FirstProject/index.jsp");
}
// 输出页面
// ...
}
JwtDataPojoにはログイン時間が存在するため、サーバー側でタイムアウトになるかどうかを具体的に確認できます。上記のコードのresolveJwtTokenメソッドは次のとおりです。
/**
* 根据传入的字符换和密码,解析为JwtToken对象
*
* @param content
* @param key
* @return JwtDataPojo
* @throws Exception
*/
public JwtDataPojo resolveJwtToken(String content, String key) throws Exception {
String jsonString = AESUtil.decrypt(content, key);
if(StringUtils.isNullOrEmpty(jsonString)) {
throw new Exception("token错误");
}
JwtDataPojo dataPojo = JSON.parseObject(jsonString, JwtDataPojo.class);
// 超过三十分钟过期
if (System.currentTimeMillis() - dataPojo.getLoginDate().getTime() > 1000 * 60 * 30) {
throw new Exception("登录过期");
}
return dataPojo;
}
上記のタイムアウトについては、自分で変更でき、Sessionの最大アイドル間隔の戦略を採用して、JwtTokenが各インターセプターで渡されることを確認した後でLoginDateを更新できます。
AESUtilのコードはこの記事を参照できます:java AESを使用してデータを暗号化および復号化する
上記で使用したFastjson 、 jarパッケージのダウンロードアドレス。
4.まとめ
前の記事では、ログインステータスの維持について説明しましたが、この記事では、Cookieの有効期間(またはJwtTokenのエージング)を変更して同じ効果を実現しています。また、サーバーで暗号化した後、セキュリティ保証もできます。
JWTに関しては、この記事の知識は少し考えて作成されます。完成したJWTの機能はより強力になります。興味があれば、自分で学ぶことができます。JWTについての記事は、後で別途書きます。
参考文献:
分割線の下で、この記事は終わりました。この記事のすべての内容は、ブロガーによって編成され、彼の理解に基づいて要約されています。エラーがある場合は、批評して修正してください。
Java Webのこのコラムは一連のブログになります。気に入ったら、引き続きフォローできます。この記事が役に立った場合は、いいね、コメントしてフォローしてください。
質問がある場合は、コメント領域にコメントを残すことができます。