web應用中實現同一個賬號,后面登錄的會把前面登錄的擠下線


  在web應用中假如沒有做會話控制,會出現這樣的情況,A登錄了賬號,B也登錄了賬號,都是同樣的賬號,A修改了信息,B會看到修改的信息,這樣的用戶體驗不好,B會覺得我沒有修改啊,為什么信息會改變。而做會話控制后,A先登錄,B再登錄,那么B會把A的登錄擠下線。

  實現思路:采用時間戳比較

  1首先用戶登錄時,后台是不需要做攔截的,前台把用戶名和密碼傳到后台,后台生成JWT格式的token給前台,並以token為key,用戶信息為value存入redis中

  2其他url路徑,過濾器會攔截請求,先判斷前台是否攜帶了token,或者是攜帶了token,但是已經失效了(redis中查不到)會直接返回前台錯誤信息,這時候會以用戶名為key,從redis中查詢token,沒有就以key為用戶名,value為token存入redis.放行請求,若從redis查詢的token和從前台傳進來的token相同,放行請求,若從redis查詢的token和從前台傳進來的token不相同,如果從前台傳遞的token的時間戳大於redis中的,則覆蓋redis中的token,否認注銷token,返回您的賬號已經在其他設備登錄,攔截請求。

public class CompareKickOutFilter extends KickOutFilter {
    @Override
    public boolean isAccessAllowed(HttpServletRequest request, HttpServletResponse response) {
        String token = request.getHeader("Authorization");
        String username = JWTUtil.getUsername(token);
        String userKey = PREFIX + username;
        RBucket<String> bucket = redissonClient.getBucket(userKey);
        String redisToken = bucket.get();

        if (StringUtils.isBlank(redisToken)) {// 第一次設置
            bucket.set(token);
        } else if (token.equals(redisToken)) { // 相同的token
            return true;
        } else {
            Long redisTokenUnixTime = JWTUtil.getClaim(redisToken, "createTime").asLong();
            Long tokenUnixTime = JWTUtil.getClaim(token, "createTime").asLong();
            if (tokenUnixTime.compareTo(redisTokenUnixTime) > 0) {
                // 傳進來的token是離現在最新的,覆蓋舊的token
                bucket.set(token);
            } else {
                // 注銷當前token
                userService.logout(token);
                sendJsonResponse(response, 4001, "您的賬號已在其他設備登錄");
                return false;
            }
        }
        return true;
    }
}

 

項目結構:

 

項目地址:https://github.com/jake1263/loginCtl

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM