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

基于SpringBoot實(shí)現(xiàn)單賬號登錄控制功能

 更新時(shí)間:2025年12月11日 08:20:54   作者:風(fēng)象南  
在很多業(yè)務(wù)場景中,我們需要控制單個(gè)賬號的登錄數(shù)量,本文介紹一種輕量級實(shí)現(xiàn)方案,靈活支持單賬號單登錄和多登錄兩種模式,有需要的小伙伴可以了解下

在很多業(yè)務(wù)場景中,我們需要控制單個(gè)賬號的登錄數(shù)量。本文介紹一種輕量級實(shí)現(xiàn)方案,靈活支持單賬號單登錄和多登錄兩種模式。

付費(fèi)系統(tǒng)場景:某在線教育平臺(tái)銷售VIP會(huì)員賬號,如果不限制登錄數(shù)量,一個(gè)賬號可能被多個(gè)用戶共享,導(dǎo)致收入損失。平臺(tái)需要確保一個(gè)付費(fèi)賬號只能有一個(gè)用戶同時(shí)在線。

企業(yè)辦公系統(tǒng):為了保證數(shù)據(jù)安全,企業(yè)OA系統(tǒng)通常要求員工賬號只能在指定設(shè)備上登錄。當(dāng)員工在新設(shè)備登錄時(shí),需要自動(dòng)踢出其他設(shè)備上的會(huì)話,防止賬號被濫用。

一、傳統(tǒng)方案的痛點(diǎn)

傳統(tǒng)的賬號登錄控制方案存在各種問題:

Session方案的局限:使用HttpSession實(shí)現(xiàn)雖然簡單,但在分布式環(huán)境下會(huì)面臨Session共享的難題。引入Spring Session雖然可以解決問題,但增加了系統(tǒng)的復(fù)雜度和依賴,對于簡單的需求來說有些"殺雞用牛刀"。

Spring Security的復(fù)雜性:Spring Security提供了強(qiáng)大的安全框架,但對于僅僅需要登錄控制的需求來說,學(xué)習(xí)成本過高,配置復(fù)雜,而且引入了很多不必要的功能。

數(shù)據(jù)庫存儲(chǔ)的性能問題:將登錄狀態(tài)存儲(chǔ)在數(shù)據(jù)庫中會(huì)導(dǎo)致每次請求都需要查詢數(shù)據(jù)庫,在高并發(fā)場景下會(huì)成為性能瓶頸。雖然可以通過緩存優(yōu)化,但又增加了系統(tǒng)復(fù)雜度。

前端狀態(tài)管理的麻煩:傳統(tǒng)的頁面跳轉(zhuǎn)方式已經(jīng)不適應(yīng)現(xiàn)代前端框架的需求。前后端分離架構(gòu)需要統(tǒng)一的API接口和狀態(tài)管理機(jī)制。

二、方案概述

2.1 核心思路

本文提出的方案基于以下幾個(gè)核心理念:

Token認(rèn)證:使用自定義Token替代傳統(tǒng)的Session機(jī)制。Token是無狀態(tài)的,可以在分布式環(huán)境下輕松擴(kuò)展,同時(shí)避免了Session共享的復(fù)雜性問題。

攔截器驗(yàn)證:通過Spring MVC的攔截器機(jī)制統(tǒng)一處理登錄驗(yàn)證。這種方式的優(yōu)點(diǎn)是不需要修改業(yè)務(wù)代碼,通過配置即可實(shí)現(xiàn)對所有請求的攔截。

接口抽象:定義清晰的SessionManager接口,將存儲(chǔ)邏輯與業(yè)務(wù)邏輯分離。這樣既可以使用Map實(shí)現(xiàn),也可以輕松切換到Redis,為系統(tǒng)擴(kuò)展提供可能。

模式切換:通過簡單的配置項(xiàng)即可在"單登錄"和"多登錄"模式之間切換,滿足不同業(yè)務(wù)場景的需求。

2.2 技術(shù)選型

核心依賴

僅使用Spring Boot Web Starter,不引入任何額外的安全框架或中間件。

存儲(chǔ)方案

單機(jī)部署:使用ConcurrentHashMap 分布式部署:通過接口抽象無縫切換到Redis

三、核心實(shí)現(xiàn)

3.1 會(huì)話管理接口

SessionManager接口是整個(gè)方案的核心,它定義了會(huì)話管理的所有基本操作:

public interface SessionManager {
    // 登錄:生成并返回Token
    String login(String username, LoginInfo loginInfo);

    // 登出:使指定Token失效
    void logout(String token);

    // 驗(yàn)證:檢查Token是否有效
    TokenInfo validateToken(String token);

    // 查詢:獲取用戶的所有活躍Token
    List getUserTokens(String username);

    // 管理:強(qiáng)制用戶下線
    void kickoutUser(String username);
}

3.2 Map實(shí)現(xiàn)方案

MapSessionManager是基于ConcurrentHashMap的具體實(shí)現(xiàn),它使用兩個(gè)Map來管理會(huì)話狀態(tài):

tokenMap:存儲(chǔ)Token到TokenInfo的映射,用于快速驗(yàn)證Token的有效性。TokenInfo包含用戶名、登錄時(shí)間、過期時(shí)間等關(guān)鍵信息。

userTokenMap:存儲(chǔ)用戶名到Token集合的映射,用于管理用戶的所有會(huì)話。這樣設(shè)計(jì)的好處是,當(dāng)需要踢出用戶時(shí),可以快速找到該用戶的所有Token并使其失效。

@Component
public class MapSessionManager implements SessionManager {
    // Token -> TokenInfo 的映射,用于驗(yàn)證
    private final Map tokenMap = new ConcurrentHashMap<>();

    // Username -> Token集合的映射,用于管理
    private final Map> userTokenMap = new ConcurrentHashMap<>();

    @Override
    public String login(String username, LoginInfo loginInfo) {
        String token = generateToken();
        TokenInfo tokenInfo = new TokenInfo(token, username, loginInfo,
            System.currentTimeMillis() + properties.getTokenExpireTime() * 1000);

        // 單登錄模式:先踢出舊會(huì)話
        if (properties.getMode() == LoginMode.SINGLE) {
            kickoutUser(username);
        }

        // 存儲(chǔ)新Token
        tokenMap.put(token, tokenInfo);
        userTokenMap.computeIfAbsent(username, k -> ConcurrentHashMap.newKeySet())
                   .add(token);

        return token;
    }
}

3.3 攔截器設(shè)計(jì)

LoginInterceptor負(fù)責(zé)攔截所有需要認(rèn)證的請求,驗(yàn)證Token的有效性。它的設(shè)計(jì)要點(diǎn)包括:

路徑排除:靜態(tài)資源、登錄接口等不需要認(rèn)證的路徑需要被排除。

Token提取:從HTTP請求頭中提取Token,支持自定義Header名稱。

驗(yàn)證邏輯:調(diào)用SessionManager驗(yàn)證Token,將驗(yàn)證結(jié)果存入請求屬性。

@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Autowired
    private SessionManager sessionManager;

    @Override
    public boolean preHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler) {
        String token = getTokenFromRequest(request);
        if (token == null) {
            return handleUnauthorized(response, &#34;請先登錄&#34;);
        }

        TokenInfo tokenInfo = sessionManager.validateToken(token);
        if (tokenInfo == null) {
            return handleUnauthorized(response, &#34;登錄已過期&#34;);
        }

        // 將用戶信息存入請求上下文
        request.setAttribute(&#34;username&#34;, tokenInfo.getUsername());
        return true;
    }
}

3.4 配置管理

LoginProperties集中管理所有可配置的參數(shù),通過Spring Boot的配置機(jī)制,可以在application.yml中靈活調(diào)整:

app:
  login:
    # 登錄模式控制
    mode: MULTIPLE  # SINGLE-單登錄, MULTIPLE-多登錄

    # Token相關(guān)配置
    token-expire-time: 1800  # 有效期30分鐘
    token-header: Authorization  # 請求頭名稱
    token-prefix: TOKEN_  # Token前綴

    # 維護(hù)配置
    enable-auto-clean: true  # 啟用自動(dòng)清理
    clean-interval: 5  # 清理間隔(分鐘)

四、API接口設(shè)計(jì)

4.1 接口定義

系統(tǒng)提供了一套RESTful API接口,支持完整的用戶會(huì)話管理功能:

接口路徑請求方法功能說明請求參數(shù)響應(yīng)數(shù)據(jù)
/api/auth/loginPOST用戶登錄username, passwordToken信息
/api/auth/logoutPOST用戶退出操作結(jié)果
/api/auth/currentGET當(dāng)前用戶用戶信息
/api/auth/onlineGET在線列表用戶名列表
/api/auth/tokensGET用戶TokensusernameToken列表
/api/auth/kickoutPOST踢出用戶username操作結(jié)果

4.2 統(tǒng)一響應(yīng)格式

所有API接口都遵循統(tǒng)一的響應(yīng)格式,便于前端處理:

{
    &#34;code&#34;: 200,        // 狀態(tài)碼
    &#34;message&#34;: &#34;成功&#34;,   // 提示信息
    &#34;data&#34;: {}          // 業(yè)務(wù)數(shù)據(jù)
}

狀態(tài)碼規(guī)范

  • 200:請求成功
  • 401:未認(rèn)證或Token失效
  • 403:權(quán)限不足
  • 500:服務(wù)器內(nèi)部錯(cuò)誤

4.3 登錄認(rèn)證流程

完整的登錄流程包括以下幾個(gè)步驟:

1. 用戶提交憑據(jù)

POST /api/auth/login
Content-Type: application/json

{
    &#34;username&#34;: &#34;admin&#34;,
    &#34;password&#34;: &#34;admin123&#34;
}

2. 服務(wù)端驗(yàn)證并生成Token 服務(wù)端驗(yàn)證用戶名密碼后,生成一個(gè)唯一的Token,包含:

  • Token字符串(UUID)
  • 用戶信息
  • 登錄時(shí)間
  • 過期時(shí)間

3. 返回Token給客戶端

{
    &#34;code&#34;: 200,
    &#34;message&#34;: &#34;登錄成功&#34;,
    &#34;data&#34;: {
        &#34;token&#34;: &#34;TOKEN_550e8400-e29b-41d4-a716-446655440000&#34;,
        &#34;username&#34;: &#34;admin&#34;,
        &#34;expireTime&#34;: 1704067200000,
        &#34;loginMode&#34;: &#34;MULTIPLE&#34;
    }
}

4. 客戶端存儲(chǔ)Token 根據(jù)用戶選擇,Token可以存儲(chǔ)在localStorage(長期有效)或sessionStorage(會(huì)話級別)。

5. 后續(xù)請求攜帶Token

GET /api/auth/current
Authorization: TOKEN_550e8400-e29b-41d4-a716-446655440000

6. 服務(wù)端驗(yàn)證Token 攔截器自動(dòng)驗(yàn)證Token的有效性,包括:

  • Token是否存在
  • Token是否過期
  • Token是否被踢出

4.4 錯(cuò)誤處理機(jī)制

當(dāng)認(rèn)證失敗時(shí),系統(tǒng)會(huì)返回明確的錯(cuò)誤信息:

{
    &#34;code&#34;: 401,
    &#34;message&#34;: &#34;Token已過期,請重新登錄&#34;,
    &#34;data&#34;: null
}

前端收到401響應(yīng)后,會(huì)自動(dòng)清除本地存儲(chǔ)的Token,并跳轉(zhuǎn)到登錄頁面。

4.5 管理功能接口

管理員可以通過專門的接口管理系統(tǒng)用戶:

獲取在線用戶:返回當(dāng)前所有在線用戶的用戶名列表,可用于監(jiān)控和統(tǒng)計(jì)。

踢出指定用戶:強(qiáng)制指定用戶下線,清除其所有Token,常用于處理異常情況。

查看用戶會(huì)話:獲取指定用戶的所有活躍Token,了解用戶的登錄狀態(tài)。

五、前端實(shí)現(xiàn)

5.1 核心實(shí)現(xiàn)

api.js:負(fù)責(zé)所有API請求的封裝,包括Token管理、請求攔截、錯(cuò)誤處理等。

頁面模塊:login.html、index.html、admin.html各自負(fù)責(zé)獨(dú)立的功能,通過import導(dǎo)入api模塊。

狀態(tài)管理:使用localStorage和sessionStorage管理Token狀態(tài),支持"記住我"功能。

5.2 Token管理機(jī)制

Token管理是前端的核心功能,實(shí)現(xiàn)了完整的生命周期管理:

// Token獲取策略
export function getToken() {
    // 優(yōu)先從localStorage獲?。ㄩL期有效)
    return localStorage.getItem('token')
        || sessionStorage.getItem('token');  // 再從sessionStorage獲取
}

// Token存儲(chǔ)策略
export function setToken(token, remember) {
    if (remember) {
        localStorage.setItem('token', token);  // 用戶選擇&#34;記住我&#34;
    } else {
        sessionStorage.setItem('token', token);  // 僅本次會(huì)話有效
    }
}

這種設(shè)計(jì)的優(yōu)勢是給了用戶選擇權(quán):隱私敏感的場景可以使用sessionStorage,確保關(guān)閉瀏覽器后自動(dòng)清除;個(gè)人設(shè)備上可以使用localStorage,提供更好的用戶體驗(yàn)。

5.3 請求攔截器

前端實(shí)現(xiàn)了一個(gè)輕量級的請求攔截器,自動(dòng)處理認(rèn)證相關(guān)的邏輯:

async function apiRequest(url, options = {}) {
    // 自動(dòng)添加Token
    const token = getToken();
    if (token) {
        options.headers = {
            ...options.headers,
            'Authorization': token
        };
    }

    const response = await fetch(url, options);

    // 統(tǒng)一處理401響應(yīng)
    if (response.status === 401) {
        clearToken();
        // 避免在登錄頁重復(fù)跳轉(zhuǎn)
        if (location.pathname !== '/login.html') {
            location.href = '/login.html';
        }
    }

    return response.json();
}

這個(gè)攔截器實(shí)現(xiàn)了:

  • 自動(dòng)攜帶Token,減少重復(fù)代碼
  • 統(tǒng)一的401處理,確保用戶在Token失效時(shí)能夠及時(shí)重新登錄

六、總結(jié)

整個(gè)方案僅依賴Spring Boot Web,不需要引入任何額外的安全框架、緩存中間件或數(shù)據(jù)庫。這使得項(xiàng)目的依賴保持最小化。

通過SessionManager接口抽象,實(shí)現(xiàn)了業(yè)務(wù)邏輯與存儲(chǔ)邏輯的完全分離。當(dāng)需要從單機(jī)擴(kuò)展到分布式時(shí),只需要實(shí)現(xiàn)一個(gè)基于Redis的SessionManager即可,業(yè)務(wù)代碼無需任何修改。

到此這篇關(guān)于基于SpringBoot實(shí)現(xiàn)單賬號登錄控制功能的文章就介紹到這了,更多相關(guān)SpringBoot賬號登錄內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue+springboot前后端分離工程跨域問題解決方案解析

    vue+springboot前后端分離工程跨域問題解決方案解析

    這篇文章主要介紹了vue+springboot前后端分離工程跨域問題解決方案解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • 如何使用SpEL表達(dá)式實(shí)現(xiàn)動(dòng)態(tài)分表查詢

    如何使用SpEL表達(dá)式實(shí)現(xiàn)動(dòng)態(tài)分表查詢

    這篇文章主要介紹了如何使用SpEL表達(dá)式實(shí)現(xiàn)動(dòng)態(tài)分表查詢,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • Java 自定義Spring框架與Spring IoC相關(guān)接口分析

    Java 自定義Spring框架與Spring IoC相關(guān)接口分析

    Spring框架是由于軟件開發(fā)的復(fù)雜性而創(chuàng)建的。Spring使用的是基本的JavaBean來完成以前只可能由EJB完成的事情。然而,Spring的用途不僅僅限于服務(wù)器端的開發(fā)
    2021-10-10
  • Java實(shí)現(xiàn)解析zip壓縮包并獲取文件內(nèi)容

    Java實(shí)現(xiàn)解析zip壓縮包并獲取文件內(nèi)容

    這篇文章主要為大家詳細(xì)介紹了如何利用Java語言實(shí)現(xiàn)頁面上傳一個(gè)源碼壓縮包,后端將壓縮包解壓,并獲取每個(gè)文件中的內(nèi)容,感興趣的可以動(dòng)手嘗試一下
    2022-07-07
  • Java List簡介_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java List簡介_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java中可變數(shù)組的原理就是不斷的創(chuàng)建新的數(shù)組,將原數(shù)組加到新的數(shù)組中,下文對Java List用法做了詳解。需要的朋友參考下吧
    2017-05-05
  • 在Spring AI中實(shí)現(xiàn)函數(shù)調(diào)用的方法

    在Spring AI中實(shí)現(xiàn)函數(shù)調(diào)用的方法

    在SpringAI中實(shí)現(xiàn)函數(shù)調(diào)用,通過反射機(jī)制與AOP技術(shù),靈活高效地處理業(yè)務(wù)邏輯,本文詳細(xì)介紹了基本原理、應(yīng)用場景及Java代碼示例,涵蓋直接調(diào)用、AOP增強(qiáng)和異步調(diào)用三種方式,需要的朋友可以參考下
    2026-05-05
  • Spring Boot系列教程之死信隊(duì)列詳解

    Spring Boot系列教程之死信隊(duì)列詳解

    這篇文章主要給大家介紹了關(guān)于Spring Boot系列教程之死信隊(duì)列的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • java實(shí)現(xiàn)基于SMTP發(fā)送郵件的方法

    java實(shí)現(xiàn)基于SMTP發(fā)送郵件的方法

    這篇文章主要介紹了java實(shí)現(xiàn)基于SMTP發(fā)送郵件的方法,實(shí)例分析了java基于SMTP服務(wù)發(fā)送郵件的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-07-07
  • Java?IO及BufferedReader.readline()出現(xiàn)的Bug

    Java?IO及BufferedReader.readline()出現(xiàn)的Bug

    這篇文章主要介紹了Java?IO及BufferedReader.readline()出現(xiàn)的Bug,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Mybatis分頁插件使用方法詳解

    Mybatis分頁插件使用方法詳解

    這篇文章主要為大家詳細(xì)介紹了Mybatis分頁插件的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-12-12

最新評論

河西区| 西和县| 兴安县| 洛南县| 太谷县| 黑水县| 永川市| 莱西市| 仙居县| 邮箱| 台中县| 邛崃市| 道孚县| 铜山县| 新和县| 洪湖市| 青铜峡市| 习水县| 锡林郭勒盟| 阿克苏市| 房产| 定陶县| 潼南县| 临潭县| 吉林省| 桦甸市| 嘉定区| 利辛县| 济南市| 漠河县| 花莲市| 澳门| 贡山| 东丽区| 奈曼旗| 九寨沟县| 许昌县| 兴仁县| 洞口县| 门头沟区| 安庆市|