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

Spring Security+JWT實(shí)現(xiàn)登錄認(rèn)證的完整實(shí)踐指南

 更新時(shí)間:2026年06月10日 09:34:10   作者:西涼的悲傷  
本文詳細(xì)介紹了SpringSecurity中的無(wú)狀態(tài)登錄認(rèn)證機(jī)制,重點(diǎn)闡述了Authentication、JWT及SecurityContextHolder的核心概念,并詳細(xì)解析了從登錄到獲取當(dāng)前用戶的完整流程,最后提出企業(yè)項(xiàng)目的最佳實(shí)踐,需要的朋友可以參考下

一、前言

在傳統(tǒng) Web 項(xiàng)目中,用戶登錄后通常使用 Session 保存登錄狀態(tài):

用戶登錄
    ↓
服務(wù)端創(chuàng)建Session
    ↓
瀏覽器保存Cookie
    ↓
后續(xù)請(qǐng)求攜帶Cookie

但是在微服務(wù)架構(gòu)中:

Gateway
    ↓
User-Service
Order-Service
Product-Service

Session 會(huì)面臨以下問(wèn)題:

  • 服務(wù)擴(kuò)容 Session 不共享
  • 微服務(wù)之間認(rèn)證困難
  • 前后端分離支持較差

因此目前企業(yè)項(xiàng)目大多采用:

Spring Security
    +
   JWT

實(shí)現(xiàn)無(wú)狀態(tài)登錄認(rèn)證。

二、Spring Security 核心對(duì)象

Spring Security 最核心的是三個(gè)對(duì)象:

SecurityContextHolder
    ↓
SecurityContext
    ↓
Authentication

1、Authentication

Authentication 表示當(dāng)前登錄用戶。

Spring Security 所有認(rèn)證信息最終都會(huì)放入 Authentication。

例如:

Authentication authentication = SecurityContextHolder
                .getContext()
                .getAuthentication();

2、Principal

Authentication 中保存真正的用戶對(duì)象:

Object principal = authentication.getPrincipal();

這個(gè)對(duì)象可以是:

User
LoginUser
JwtUser
GlobalJwtUser

Spring Security 并不關(guān)心具體類型。

只要實(shí)現(xiàn)認(rèn)證成功即可。

3、SecurityContextHolder

用于保存當(dāng)前請(qǐng)求認(rèn)證信息。

結(jié)構(gòu)如下:

SecurityContextHolder
        ↓
SecurityContext
        ↓
Authentication
        ↓
    JwtUser

三、JWT 登錄認(rèn)證整體流程

完整認(rèn)證流程如下:

用戶登錄

    ↓

用戶名密碼校驗(yàn)

    ↓

生成JWT

    ↓

返回前端


================================

后續(xù)請(qǐng)求

Authorization: Bearer xxx

    ↓

JwtAuthenticationFilter

    ↓

解析JWT

    ↓

獲取JwtUser

    ↓

構(gòu)造Authentication

    ↓

放入SecurityContext

    ↓

Controller
Service

四、Bearer 是什么

很多人第一次接觸 JWT 都會(huì)看到:

Authorization: Bearer eyJhbGciOiJIUzI1Ni...

這里:

Bearer

表示認(rèn)證方案。

格式遵循 HTTP 標(biāo)準(zhǔn):

Authorization: <認(rèn)證方式> <認(rèn)證信息>

例如:

Authorization: Basic xxxxx
Authorization: Bearer xxxxx

JWT 標(biāo)準(zhǔn)寫法就是:

Authorization: Bearer token

Spring Security 默認(rèn)也是按照這個(gè)格式解析。

五、自定義用戶對(duì)象

企業(yè)項(xiàng)目一般不會(huì)直接使用 User。

通常會(huì)定義自己的用戶對(duì)象:

@Data
public class JwtUser {

    private Long userId;

    private String username;

    private String deptCode;

}

這個(gè)對(duì)象最終會(huì)存入 Spring Security 上下文。

六、登錄成功生成 JWT

登錄接口:

@PostMapping("/login")
public String login(LoginRequest request){

    Authentication authentication =
            authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            request.getUsername(),
                            request.getPassword()));

    JwtUser user =
            (JwtUser) authentication.getPrincipal();

    return jwtService.generateToken(user);
}

認(rèn)證成功:

用戶名密碼
    ↓
數(shù)據(jù)庫(kù)校驗(yàn)
    ↓
生成JWT
    ↓
返回前端

返回結(jié)果:

{
  "token":"eyJhbGciOiJIUzI1Ni..."
}

七、JWT 過(guò)濾器解析 Token

企業(yè)項(xiàng)目核心代碼基本都在過(guò)濾器中。

例如:

public class JwtAuthenticationFilter
        extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain filterChain)
            throws IOException, ServletException {

        String token =
                request.getHeader("Authorization");

        if(token != null){

            JwtUser user =
                    parseToken(token);

            JwtAuthentication authentication =
                    new JwtAuthentication(user);

            SecurityContextHolder
                    .getContext()
                    .setAuthentication(authentication);
        }

        filterChain.doFilter(request,response);
    }
}

作用:

請(qǐng)求進(jìn)入

↓

解析JWT

↓

獲得JwtUser

↓

存入Spring Security上下文

八、自定義 Authentication

Spring Security 實(shí)際保存的是 Authentication。

因此一般會(huì)定義:

public class JwtAuthentication
        extends AbstractAuthenticationToken {

    private final JwtUser jwtUser;

    public JwtAuthentication(JwtUser jwtUser) {

        super(null);

        this.jwtUser = jwtUser;

        setAuthenticated(true);
    }

    @Override
    public Object getPrincipal() {

        return jwtUser;
    }

    @Override
    public Object getCredentials() {

        return null;
    }
}

重點(diǎn):

getPrincipal()

返回:

JwtUser

九、為什么 setAuthentication 如此重要

認(rèn)證成功后:

SecurityContextHolder
        .getContext()
        .setAuthentication(authentication);

實(shí)際上完成了:

SecurityContextHolder
        ↓
Authentication
        ↓
JwtUser

的綁定。

這是整個(gè) Spring Security 認(rèn)證體系最關(guān)鍵的一步。

如果沒(méi)有這一步:

SecurityContextHolder
        .getContext()
        .getAuthentication();

獲取到的就是空。

十、Controller 如何自動(dòng)獲得當(dāng)前用戶

很多項(xiàng)目中會(huì)看到:

@PostMapping("/save")
public void save(
        @CurrentJwtUser JwtUser user) {

}

為什么能夠自動(dòng)注入?

1、自定義注解

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@AuthenticationPrincipal
public @interface CurrentJwtUser {

}

本質(zhì)上:

@CurrentJwtUser

就是:

@AuthenticationPrincipal

的二次封裝。

2、Spring Security 自動(dòng)解析

Spring Security 內(nèi)部提供:

AuthenticationPrincipalArgumentResolver

專門處理:

@AuthenticationPrincipal

參數(shù)。

執(zhí)行流程:

Controller請(qǐng)求

    ↓

發(fā)現(xiàn)參數(shù)

@CurrentJwtUser

    ↓

讀取Authentication

    ↓

調(diào)用

authentication.getPrincipal()

    ↓

獲得JwtUser

    ↓

自動(dòng)注入

因此:

@CurrentJwtUser JwtUser user

實(shí)際上等價(jià)于:

JwtUser user =
(JwtUser)
SecurityContextHolder
        .getContext()
        .getAuthentication()
        .getPrincipal();

十一、業(yè)務(wù)代碼獲取當(dāng)前用戶

很多 Service 層也需要當(dāng)前用戶。

通常封裝工具類:

public class SecurityUtil {

    public static JwtUser currentUser(){

        Authentication authentication =
                SecurityContextHolder
                        .getContext()
                        .getAuthentication();

        if(authentication == null){
            return null;
        }

        return (JwtUser)
                authentication.getPrincipal();
    }

}

使用:

JwtUser user =
        SecurityUtil.currentUser();

Long userId =
        user.getUserId();

十二、完整認(rèn)證鏈路分析

整個(gè)流程串起來(lái)如下:

用戶請(qǐng)求

Authorization: Bearer token

        ↓

JwtAuthenticationFilter

        ↓

解析JWT

        ↓

JwtUser

        ↓

JwtAuthentication

        ↓

SecurityContextHolder

        ↓

Controller

        ↓

@AuthenticationPrincipal

        ↓

Authentication.getPrincipal()

        ↓

JwtUser自動(dòng)注入

十三、為什么 Controller 和 Service 獲取的是同一個(gè)用戶

Controller:

@CurrentJwtUser JwtUser user

Service:

SecurityUtil.currentUser()

雖然寫法不同。

但最終訪問(wèn)的都是:

SecurityContextHolder
        ↓
SecurityContext
        ↓
Authentication
        ↓
JwtUser

因此拿到的是同一個(gè)對(duì)象。

十四、企業(yè)項(xiàng)目最佳實(shí)踐

推薦架構(gòu):

Spring Security
        +
JWT
        +
Gateway
        +
Redis

流程:

登錄

↓

認(rèn)證中心

↓

JWT

↓

Gateway統(tǒng)一校驗(yàn)

↓

解析用戶信息

↓

寫入上下文

↓

業(yè)務(wù)服務(wù)直接獲取用戶

優(yōu)點(diǎn):

  • 無(wú)狀態(tài)認(rèn)證
  • 支持微服務(wù)
  • 支持水平擴(kuò)容
  • 支持統(tǒng)一權(quán)限控制
  • 支持單點(diǎn)登錄

十五、總結(jié)

Spring Security + JWT 的核心只有一句話:

SecurityContextHolder
        .getContext()
        .setAuthentication(authentication);

認(rèn)證成功后:

JwtUser
    ↓
JwtAuthentication
    ↓
SecurityContextHolder

隨后:

@AuthenticationPrincipal

或者:

SecurityContextHolder

都能獲取當(dāng)前登錄用戶。

整個(gè)認(rèn)證鏈路可以概括為:

JWT
    ↓
Filter
    ↓
JwtUser
    ↓
Authentication
    ↓
SecurityContextHolder
    ↓
Controller/Service

理解了這條鏈路,就真正理解了 Spring Security 的認(rèn)證機(jī)制。

以上就是Spring Security+JWT實(shí)現(xiàn)登錄認(rèn)證的完整實(shí)踐指南的詳細(xì)內(nèi)容,更多關(guān)于Spring Security JWT登錄認(rèn)證的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論

锦州市| 文水县| 郑州市| 博湖县| 旅游| 连平县| 嵊泗县| 台东市| 措勤县| 湖南省| 乐安县| 乌恰县| 长泰县| 磐安县| 连平县| 新化县| 班戈县| 遵义县| 梁河县| 玛纳斯县| 阳原县| 彰化县| 岐山县| 拉萨市| 玉山县| 汉寿县| 桑植县| 剑河县| 日土县| 达州市| 十堰市| 祁门县| 喀喇沁旗| 阳东县| 孟州市| 龙门县| 营山县| 宣城市| 肇东市| 如皋市| 永登县|