使用session以及在session中加入token

通過使用session以及在session中加入token,來驗證同一個操作人員是否進行了併發重複的請求,在後一個請求到來時,使用session中的token驗證請求中的token是否一致,當不一致時,被認爲是重複提交,將不准許通過。

整個流程可以由如下流程來表述:

客戶端申請token
服務器端生成token,並存放在session中,同時將token發送到客戶端
客戶端存儲token,在請求提交時,同時發送token信息
服務器端統一攔截用戶的所有請求,驗證當前請求是否需要被驗證(不是所有請求都驗證重複提交)
驗證session中token是否和用戶請求中的token一致,如果一致則放行
session清除會話中的token,爲下一次的token生成作準備
併發重複請求到來,驗證token和請求token不一致,請求被拒絕

請求之前申請token,然後在真正請求時將token發送給服務端進行判斷。例如,在加載這個頁面時請求申請token,點擊搶的按鈕時,將token以參數的形式傳給服務器端,進行判斷。多次點擊按鈕後–併發請求,那麼服務器端會攔截所有請求,進行token對比,由於第一次的請求通過後,session便清除了會話中的token,故再次對比即不同,便被攔截在外了。

由以上的流程,我們整個實現需要以下幾個東西

token生成器,負責生成token
客戶token請求處理action,負責處理客戶請求,並返回token信息
token攔截器,用於攔截指定的請求是否需要驗證token
token請求攔截標識,用於標識哪些請求是需要被攔截的
客戶端token請求處理方法,用於請求token,並存放於特定操作中,並在提交時發送到請求中

token生成器
token生成器在這裏使用了一個隨機數來實現,即隨機生成一個數字,即實現token生成,如下所示:

private static final Random random = new Random(System.currentTimeMillis());
public static final String TOKENPARAM = "session-token";
 
/** 生成一個token */
public static synchronized String generateToken(HttpSession session) {
    String s = String.valueOf(random.nextLong());
    session.setAttribute(TOKENPARAM, s);
    return s;
}

token請求處理action
請求處理action,即接收相應的請求,然後直接返回相對應的token即可,如下即爲一個爲ajax請求生成token的處理action:

public String generateTokenAjax() {
    String token = SessionTokenGenerator.generateToken(ServletActionContext.getRequest().getSession());
    AjaxSupport.sendSuccessText(token);
    return NONE;
}

token請求攔截標識

攔截標識,即表示哪些方法需要被攔截,這裏可以使用註解來實現,即在要攔截的方法上追加類似@TokenNeed的註解,或者使用配置文件,將需要攔截的方法列表記錄在配置文件中,在本文中,使用了一個配置文件來記錄

token攔截器

token攔截器實現了我們所需要的攔截處理,在當碰到需要攔截的方法請求中,將同步進行token的判斷和處理,並根據處理結果判斷是否該繼續放行或攔截之:
public String intercept(ActionInvocation invocation) throws  Exception {
    String action = invocation.getProxy().getAction().getClass().getName();
    String method = invocation.getProxy().getMethod();
    final HttpSession session = ServletActionContext.getRequest().getSession();
    if(includeMethodSet.contains(action + "." + method)) {
        synchronized(session) {
            String paramSessionToken = ServletActionContext.getRequest().getParameter(SessionTokenGenerator.TOKENPARAM);
            String sessionSessionToken = (String) session.getAttribute(SessionTokenGenerator.TOKENPARAM);
            if(sessionSessionToken == null || paramSessionToken == null || !paramSessionToken.equals(sessionSessionToken))
                return fail();
            session.removeAttribute(SessionTokenGenerator.TOKENPARAM);
        }
    }
    return invocation.invoke();
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章