最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java實現(xiàn)多設(shè)備同時登錄或強制下線

 更新時間:2023年07月23日 09:12:49   作者:臨時工  
本文主要介紹了java實現(xiàn)多設(shè)備同時登錄或強制下線,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言:你有沒有遇到過這樣的需求,產(chǎn)品要求實現(xiàn)同一個用戶根據(jù)后臺設(shè)置允許同時登錄,或者不準同時登錄時,需要強制踢下線前一個的場景。本文將帶領(lǐng)大家實現(xiàn)一個簡單的這種場景需求。

先來看一下簡單的時序圖,方便后續(xù)理解。

首先我們需要有一個后臺設(shè)置開關(guān)來控制允不允許用戶多設(shè)備同時登錄的功能(沒有也無妨,假定允許),其次在登錄后,需要保存用戶的userId-token的關(guān)系緩存。再回頭看上面的時序圖,是不是已經(jīng)能理解實現(xiàn)的原理了。

如果你的架構(gòu)是微服務(wù),那么可以使用redis來存登錄關(guān)系緩存,單體架構(gòu)可以直接存session即可。本文是微服務(wù)架構(gòu),所以采用的是redis。

本文的前提都是基于同一個用戶的情況下,下文不再贅述。

1 構(gòu)造登錄緩存關(guān)系

如果要實現(xiàn)同一用戶多設(shè)備同時登錄,那必然需要在session(微服務(wù)中可以用redis做session共享)中能找到用戶的每一個登錄狀態(tài),如果只是簡單的緩存用戶信息是實現(xiàn)不了的,登錄時那就必須要有一個唯一值token,這樣每次登錄token不一樣,但是指向的用戶是同一個。

usertoken中維護的是前綴:用戶id,這里不需要維護多個,因為用的reids的hash數(shù)據(jù)類型,多個登錄時,添加新行即可;user部分,這里維護的是多個,即登錄一次就有一條記錄;因為根據(jù)業(yè)務(wù)需要,后續(xù)需要從緩存中獲取用戶其他信息。

  • 允許多設(shè)備同時登錄:usertoken只有1條,user可能會有多條
  • 不允許多設(shè)備同時登錄(有則強制下線):usertoken只有1條,user只有1條
    /**
     * 登錄成功后緩存用戶信息
     *
     * @param req
     * @return
     */
    public void cacheUserInfo(CacheUserInfoReqDTO req) {
        // 1、緩存用戶信息
        cacheUser(req);
        cacheAuth(req.getUid(), req.getRoles(), req.getPermissions());
        // 2、更新token與userId關(guān)系
        String userTokenRelationKey = RedisKeyHelper.getUserTokenRelationKey(req.getEntId() + SymbolConstant.COLON + req.getUid());
        redisAdapter.set(userTokenRelationKey, req.getToken(), RedisTtl.USER_LOGIN_SUCCESS);
    }

2 過濾器配置

登錄鑒權(quán)部分和用戶登錄狀態(tài)上下文不在本文范圍內(nèi),此處忽略

登錄成功后,每一個請求到達過濾器時,通過請求header中的token來獲取登錄信息;因為我們存的緩存key前綴都包含userId,所以要想得到用戶信息,需要使用到redis的scan命令來獲取。(scan最好配置count來限制,保證性能)

@Override
protected Mono<Void> innerFilter(ServerWebExchange exchange, WebFilterChain chain) {
        String token = filterContext.getToken();
        if (StringUtils.isBlank(token)) {
            throw new DataValidateException(GatewayReturnCodes.TOKEN_MISSING);
        }
        // scan獲取user的key
        String userKey = "";
        Set<String> scan = redisAdapter.scan(GatewayRedisKeyPrefix.USER_KEY.getKey() + "*" + token);
        if (scan.isEmpty()) {
            throw new DataValidateException(GatewayReturnCodes.TOKEN_EXPIRED_LOGIN_SUCCESS);
        }
        userKey = scan.iterator().next();
        MyUser myUser = (MyUser) redisAdapter.get(userKey);
        if (myUser == null) {
            throw new BusinessException(GatewayReturnCodes.TOKEN_EXPIRED_LOGIN_SUCCESS);
        }
        // 將用戶信息塞入http header
        // do something...
        return chain.filter(exchange.mutate().request(newServerHttpRequest).build());
    }

這樣保證即使有多設(shè)備同時登錄,也能獲取到登錄信息和上下文。

3 如何做強制下線呢?

其實也很簡單,在登錄前可以通過AOP方式做校驗,如果已登錄了,那么這里就清除session或用戶緩存,再繼續(xù)進行正常登錄即可。再簡單一點可以直接在登錄service中添加校驗

核心邏輯

 String userTokenRelationKey = RedisKeyHelper.getUserTokenRelationKey(req.getEntId() + SymbolConstant.COLON + userEntList.get(0).getUserId());
            String redisToken = (String) redisAdapter.get(userTokenRelationKey);
if (StringUtils.isNotEmpty(redisToken) && !redisToken.equals(token)) {
        throw new BusinessException(UserReturnCodes.MULTI_DEVICE_LOGIN);
            }

這里用于判斷是否已有登錄,并返回給前端提示。用于前端其他業(yè)務(wù)處理如果不需要給前端提示,不用返回前端,直接進行清除session或用戶緩存邏輯。

 String userTokenRelationKey = RedisKeyHelper.getUserTokenRelationKey(req.getEntId() + SymbolConstant.COLON + userEntity.getId());
    // 獲取當(dāng)前已用戶的登錄token
    String redisToken = (String) redisAdapter.get(userTokenRelationKey);
    // 踢下線之前全部登錄
    Response<Void> exitLoginResponse = gatewayRpc.allExit(ExitLoginReqDTO.builder().token(redisToken).userId(userEntity.getId()).build());

4 演示

演示強制下線

這里我用用戶id為4做演示

先正常第一次登錄,提示成功,并且redis中有1條user記錄

再次登錄,我這里是返回給前端處理了,所以會有提示信息。

前端效果

最后,擴展一下,如果要實現(xiàn)登錄后強制修改默認密碼、登錄時間段限制等場景,你會怎么實現(xiàn)呢?

到此這篇關(guān)于java實現(xiàn)多設(shè)備同時登錄或強制下線的文章就介紹到這了,更多相關(guān)java 多設(shè)備同時登錄或強制下線內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Docker?Compose+Jenkins自動化部署流程圖文教程

    Docker?Compose+Jenkins自動化部署流程圖文教程

    Jenkins是一款非常流行的開源持續(xù)集成工具,廣泛用于項目開發(fā),具有自動化構(gòu)建、測試和部署等功能,這篇文章主要介紹了Docker?Compose+Jenkins自動化部署流程的相關(guān)資料,文中通過圖文介紹的非常詳細,需要的朋友可以參考下
    2026-04-04
  • Java處理科學(xué)計數(shù)法數(shù)字方式

    Java處理科學(xué)計數(shù)法數(shù)字方式

    這篇文章主要介紹了Java處理科學(xué)計數(shù)法數(shù)字方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • Java中的List和MySQL中的varchar相互轉(zhuǎn)換的解決方案

    Java中的List和MySQL中的varchar相互轉(zhuǎn)換的解決方案

    實體類中有一個 List<String> 類型的屬性,對應(yīng)于 MySQL 表里的 varchar 字段,使用 MyBatis 添加或查詢時能互相轉(zhuǎn)換,本文給大家介紹Java中的List和MySQL中的varchar相互轉(zhuǎn)換的解決方案,需要的朋友可以參考下
    2024-06-06
  • Spring+SpringMVC+Hibernate項目環(huán)境搭建的步驟(圖文)

    Spring+SpringMVC+Hibernate項目環(huán)境搭建的步驟(圖文)

    這篇文章主要介紹了Spring+SpringMVC+Hibernate項目環(huán)境搭建的步驟(圖文),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • Springboot配置過濾器實現(xiàn)過程解析

    Springboot配置過濾器實現(xiàn)過程解析

    這篇文章主要介紹了Springboot配置過濾器實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-08-08
  • 基于Java子線程中的異常處理方法(通用)

    基于Java子線程中的異常處理方法(通用)

    下面小編就為大家?guī)硪黄贘ava子線程中的異常處理方法(通用)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • java讀寫oracle的blob字段示例

    java讀寫oracle的blob字段示例

    這篇文章主要介紹了java讀寫oracle的blob字段示例,需要的朋友可以參考下
    2014-02-02
  • 從0開始教你開發(fā)一個springboot應(yīng)用

    從0開始教你開發(fā)一個springboot應(yīng)用

    這篇文章主要為大家介紹了從0開始開發(fā)一個springboot應(yīng)用教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • 分析 Java Stream 的 peek使用實踐與副作用處理方案

    分析 Java Stream 的 peek使用實踐與副作用處理方案

    Stream API的peek操作是中間操作,用于觀察元素但不終止流,其副作用風(fēng)險包括線程安全、順序混亂及性能問題,合理使用場景有限,本文給大家介紹Java Stream的peek使用實踐與副作用,感興趣的朋友跟隨小編一起看看吧
    2025-09-09
  • 線程池之jdk1.8 Executors創(chuàng)建線程池的幾種方式

    線程池之jdk1.8 Executors創(chuàng)建線程池的幾種方式

    這篇文章主要介紹了線程池之jdk1.8 Executors創(chuàng)建線程池的幾種方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08

最新評論

德钦县| 苏州市| 西乌珠穆沁旗| 交城县| 科尔| 延津县| 陇南市| 枣阳市| 景洪市| 开封市| 岳普湖县| 安康市| 故城县| 莆田市| 宁国市| 大连市| 江阴市| 策勒县| 正宁县| 江城| 东源县| 长沙县| 渑池县| 灵石县| 丰宁| 曲靖市| 三河市| 同德县| 兴义市| 岳阳市| 府谷县| 虹口区| 弋阳县| 乐都县| 平舆县| 武清区| 昌都县| 周宁县| 綦江县| 沅陵县| 麦盖提县|