首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java TokenProcessor 令牌驗證工具類:防止表單重複提交實作

     編輯:Java 相關知識

核心功能

  • 生成唯一 Token 存入 Session
  • 驗證請求參數 Token 與 Session 中是否一致
  • 驗證通過後移除 Token (一次性使用)

完整工具類代碼

public class TokenProcessor {
    private long previous;
    private static TokenProcessor instance = new TokenProcessor();
    public static final String FORM_TOKEN_KEY = "FORM_TOKEN_KEY";

    private TokenProcessor() {}

    public static TokenProcessor getInstance() { return instance; }

    // 驗證 Token (從請求參數取得)
    public synchronized boolean isTokenValid(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session == null) return false;
        String saved = (String) session.getAttribute(FORM_TOKEN_KEY);
        String token = request.getParameter(FORM_TOKEN_KEY);
        return saved != null && token != null && saved.equals(token);
    }

    // 重載:直接傳入 token 字串驗證
    public synchronized boolean isTokenValid(HttpServletRequest request, String token) {
        HttpSession session = request.getSession(false);
        if (session == null) return false;
        String saved = (String) session.getAttribute(FORM_TOKEN_KEY);
        return saved != null && token != null && saved.equals(token);
    }

    // 移除 Token
    public synchronized void reset(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session != null) session.removeAttribute(FORM_TOKEN_KEY);
    }

    // 生成並儲存 Token
    public synchronized void saveToken(HttpServletRequest request) {
        HttpSession session = request.getSession();
        try {
            byte[] id = session.getId().getBytes();
            long current = System.currentTimeMillis();
            if (current == previous) current++;
            previous = current;
            byte[] now = String.valueOf(current).getBytes();

            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(id);
            md.update(now);
            String token = toHex(md.digest());
            session.setAttribute(FORM_TOKEN_KEY, token);
        } catch (NoSuchAlgorithmException e) {
            // log error
        }
    }

    // 位元組陣列轉十六進制字串
    private String toHex(byte[] buffer) {
        StringBuffer sb = new StringBuffer(buffer.length * 2);
        for (byte b : buffer) {
            sb.append(Character.forDigit((b & 0xF0) >> 4, 16));
            sb.append(Character.forDigit(b & 0x0F, 16));
        }
        return sb.toString();
    }
}

使用流程

  1. 表單頁面渲染前:TokenProcessor.getInstance().saveToken(request);
  2. 表單隱藏域帶入 Token:<input type="hidden" name="FORM_TOKEN_KEY" value="${sessionScope.FORM_TOKEN_KEY}">
  3. 提交處理 Action 中:
    if (!TokenProcessor.getInstance().isTokenValid(request)) { return "repeat_submit"; }
    TokenProcessor.getInstance().reset(request); // 驗證通過後清除

原理說明

Token 由 Session ID + 當前時間毫秒數經 MD5 雜湊生成,極難偽造。Session 機制確保每個使用者獨立。驗證後即刻移除,防止重複提交 (Refresh/F5)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved