亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java實(shí)現(xiàn)JWT令牌的示例代碼

 更新時(shí)間:2025年09月25日 08:30:16   作者:一只游魚  
JWT是一種無(wú)狀態(tài)認(rèn)證方案,用于前后端分離項(xiàng)目,后端生成包含用戶信息的token,前端保存并隨請(qǐng)求頭攜帶,后端通過驗(yàn)證token簽名、有效期等確保安全,實(shí)現(xiàn)跨服務(wù)身份認(rèn)證,感興趣的可以了解一下

一、簡(jiǎn)介

JWT (JSON Web Token) 是一種 跨服務(wù)、跨語(yǔ)言的認(rèn)證解決方案,常用于前后端分離項(xiàng)目(比如 Spring Boot + Vue)。
它的主要作用是:

  1. 身份認(rèn)證
    • 用戶登錄成功后,后端生成一個(gè) JWT 返回給前端。
    • 前端每次請(qǐng)求時(shí)帶上這個(gè) JWT,后端根據(jù)它來(lái)確認(rèn)“你是誰(shuí)”。
  2. 無(wú)狀態(tài)認(rèn)證(不依賴 session
    • 傳統(tǒng)的 session 登錄需要服務(wù)器保存狀態(tài),用戶多了容易占用大量?jī)?nèi)存。
    • JWT 是 自包含的,不需要服務(wù)器保存用戶狀態(tài),后端只要驗(yàn)證 token 就行。
  3. 安全傳遞信息
    • JWT 由三部分組成:Header.Payload.Signature。
    • Payload 里可以存儲(chǔ)用戶 ID、角色、過期時(shí)間等信息。
    • Signature 簽名部分保證 token 不會(huì)被篡改。

二、實(shí)現(xiàn)流程

  1. 用戶在 Vue 前端輸入用戶名、密碼 → 發(fā)送到 Spring Boot 登錄接口。
  2. Spring Boot 驗(yàn)證賬號(hào)密碼成功后 → 生成 JWT → 返回給前端。
  3. Vue 將 JWT 保存(通常存在 localStorage 或 sessionStorage)。
  4. 前端每次請(qǐng)求后端 API 時(shí),在請(qǐng)求頭 Authorization 里帶上:Authorization: Bearer <token>
  5. Spring Boot 攔截請(qǐng)求,驗(yàn)證 JWT 是否有效:
    • 簽名是否正確?
    • 是否過期?
    • 是否被篡改?
    • 驗(yàn)證通過才放行,否則返回 401(未認(rèn)證)。

如圖:

三、實(shí)戰(zhàn)

這里我們用spring boot + vue 來(lái)演示,

在配置中:

# JWT
#密鑰 注意密鑰要夠長(zhǎng)58位
jwt.secret=abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+
#過期時(shí)間
jwt.expiration= 3600000

創(chuàng)建工具類:

@Value("${jwt.secret}")
private String secret;
 
@Value("${jwt.expiration}")
private long expiration; // 例如 3600000 = 1小時(shí)
 
// 生成 token
public String generateToken(String username) {
    Date now = new Date();
    Date expiryDate = new Date(now.getTime() + expiration);
 
    return Jwts.builder()
            .setSubject(username)
            .setIssuedAt(now)
            .setExpiration(expiryDate)
            .signWith(Keys.hmacShaKeyFor(secret.getBytes()))
            .compact();
}
 
// 獲取用戶名
public String getUsernameFromToken(String token) {
    return Jwts.parserBuilder()
            .setSigningKey(Keys.hmacShaKeyFor(secret.getBytes()))
            .build()
            .parseClaimsJws(token)
            .getBody()
            .getSubject();
}
 
// 驗(yàn)證 token
public boolean validateToken(String token) {
    try {
        Jwts.parserBuilder()
                .setSigningKey(Keys.hmacShaKeyFor(secret.getBytes()))
                .build()
                .parseClaimsJws(token);
        return true;
    } catch (JwtException | IllegalArgumentException e) {
        return false;
    }
}

創(chuàng)建SecurityConfig文件

@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
    String path = exchange.getRequest().getURI().getPath();
 
 
    // 1. 放行登錄注冊(cè)
    if (path.startsWith("/user/login") || path.startsWith("/user/register") || path.startsWith("/chat-stream")) {
        return chain.filter(exchange);
    }
    //如果沒有Authorization頭,返回401
   if (!exchange.getRequest().getHeaders().containsKey("Authorization")) {
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        return exchange.getResponse().setComplete();
    }
 
    // 2. 處理Authorization頭
    String authHeader = exchange.getRequest().getHeaders().getFirst("Authorization");
    if (!authHeader.startsWith("Bearer ")) {
        // 無(wú)有效Token,返回401
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        return exchange.getResponse().setComplete();
    }
 
    // 3. 解析Token
    String token = authHeader.substring(7);
    if (!jwtUtil.validateToken(token)) {
        // Token驗(yàn)證失?。ㄟ^期、簽名錯(cuò)誤等),返回401并打印日志
        System.out.println("JWT驗(yàn)證失?。篢oken無(wú)效或過期 - " + token);
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        return exchange.getResponse().setComplete();
    }
 
    // 4. Token有效,設(shè)置認(rèn)證信息到安全上下文
    String username = jwtUtil.getUsernameFromToken(token);
    Authentication auth = new UsernamePasswordAuthenticationToken(
            username, null, Collections.emptyList() // 無(wú)權(quán)限,可根據(jù)需求添加
    );
 
    // 5. 傳遞認(rèn)證信息并繼續(xù)執(zhí)行過濾鏈
    return chain.filter(exchange)
            .contextWrite(ReactiveSecurityContextHolder.withAuthentication(auth));
}

接著創(chuàng)建JwtFilter

@Autowired
private JwtUtil jwtUtil;
 
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
    String path = exchange.getRequest().getURI().getPath();
 
 
    // 1. 放行登錄注冊(cè)
    if (path.startsWith("/user/login") || path.startsWith("/user/register") || path.startsWith("/chat-stream")) {
        return chain.filter(exchange);
    }
 
    // 2. 處理Authorization頭
    String authHeader = exchange.getRequest().getHeaders().getFirst("Authorization");
    if (!authHeader.startsWith("Bearer ")) {
        // 無(wú)有效Token,返回401
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        return exchange.getResponse().setComplete();
    }
 
    // 3. 解析Token
    String token = authHeader.substring(7);
    if (!jwtUtil.validateToken(token)) {
        // Token驗(yàn)證失?。ㄟ^期、簽名錯(cuò)誤等),返回401并打印日志
        System.out.println("JWT驗(yàn)證失?。篢oken無(wú)效或過期 - " + token);
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        return exchange.getResponse().setComplete();
    }
 
    // 4. Token有效,設(shè)置認(rèn)證信息到安全上下文
    String username = jwtUtil.getUsernameFromToken(token);
    Authentication auth = new UsernamePasswordAuthenticationToken(
            username, null, Collections.emptyList() // 無(wú)權(quán)限,可根據(jù)需求添加
    );
 
    // 5. 傳遞認(rèn)證信息并繼續(xù)執(zhí)行過濾鏈
    return chain.filter(exchange)
            .contextWrite(ReactiveSecurityContextHolder.withAuthentication(auth));
}

在控制層中,我們就可以在登錄邏輯中創(chuàng)建、返回給密鑰了:

//生成token
String token = jwtUtil.generateToken(user.getUserName());
//封裝返回?cái)?shù)據(jù)
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.put("token", token);

在前端中,處理登錄請(qǐng)求,將登錄成功后后端返回的token保存到瀏覽器:

const onFinish = async (values) => {
  loading.value = true
  try {
    if (isLogin.value) {
 
      //加密數(shù)據(jù)
      const encrypted = Encrypt(JSON.stringify(values))
      // 實(shí)現(xiàn)登錄邏輯
      const response = await request.post('/user/login', { data: encrypted })
 
      //保存token
      localStorage.setItem("token", JSON.parse(response.data).data.token)
 
     
      alert("登錄成功")
 
 
      // 刷新頁(yè)面
      // window.location.reload()
    } else {
      //加密數(shù)據(jù)
      const encrypted = Encrypt(JSON.stringify(values))
      // 實(shí)現(xiàn)注冊(cè)邏輯
      const response = await request.post('/user/register', { data: encrypted })
      console.log('注冊(cè):', values)
    }
  } catch (error) {
    console.error(error)
    alert("登錄失敗")
  } finally {
    loading.value = false
  }
}

創(chuàng)建request.Js,將保存到本地瀏覽器的token放到請(qǐng)求頭中:

import axios from "axios";
const request = axios.create({
  baseURL: "/api",
  timeout: 30000, // 修改為30秒
  responseType: "stream" // 流式響應(yīng)
});
// 請(qǐng)求攔截器:自動(dòng)攜帶 token
request.interceptors.request.use(
  (config) => {
  const token = localStorage.getItem("token");
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);
export default request;

發(fā)送請(qǐng)求:

// 刪除
const deleteChat = (id) => {
  Modal.confirm({
    title: '確認(rèn)刪除',
    content: '確定要?jiǎng)h除此對(duì)話嗎?(對(duì)話歷史也將會(huì)全部刪除)',
    okText: '確認(rèn)',
    cancelText: '取消',
    onOk() {
      // 調(diào)用后端接口刪除對(duì)話
      eventSource?.close();
      request.delete(`/chat/delete/${id}`)
        .then((response) => {
          if (response.data.code === "200") {  
            //顯示更新成功
            message.success('刪除成功');
            //刷新對(duì)話列表
            getChatList();
          } else {
            //顯示更新失敗
            message.error('刪除失敗');
          }
        })
        .catch(err => {
          message.error('刪除失敗');
          // console.error('刪除失敗:', err);
        });
    },
    onCancel() {
      console.log('取消刪除');
    },
  });
};

運(yùn)行可以看到,登錄成功后后端成功返回token:

Token成功保存:

如果token國(guó)企或者錯(cuò)誤:

再次請(qǐng)求會(huì)顯示401無(wú)權(quán)限報(bào)錯(cuò)

到此這篇關(guān)于Java實(shí)現(xiàn)JWT令牌的示例代碼的文章就介紹到這了,更多相關(guān)Java JWT令牌內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

  • 什么是RESTful?API,有什么作用

    什么是RESTful?API,有什么作用

    提到RESTful?API大家勢(shì)必或多或少聽說(shuō)過,但是什么是RESTful?API??如何理解RESTful?API?呢?今天咱們就來(lái)聊聊這個(gè)RESTful?API
    2023-11-11
  • SpringCloud中NacosNamingService的作用詳解

    SpringCloud中NacosNamingService的作用詳解

    這篇文章主要介紹了SpringCloud中NacosNamingService的作用詳解,NacosNamingService類完成服務(wù)實(shí)例注冊(cè),撤銷與獲取服務(wù)實(shí)例操作,NacosNamingService初始化采用單例模式,使用反射生成,需要的朋友可以參考下
    2023-11-11
  • SpringCloud服務(wù)接口調(diào)用OpenFeign及使用詳解

    SpringCloud服務(wù)接口調(diào)用OpenFeign及使用詳解

    這篇文章主要介紹了SpringCloud服務(wù)接口調(diào)用——OpenFeign,在學(xué)習(xí)Ribbon時(shí),服務(wù)間調(diào)用使用的是RestTemplate+Ribbon實(shí)現(xiàn),而Feign在此基礎(chǔ)上繼續(xù)進(jìn)行了封裝,使服務(wù)間調(diào)用變得更加方便,需要的朋友可以參考下
    2023-04-04
  • 關(guān)于Spring項(xiàng)目對(duì)JDBC的支持與基本使用詳解

    關(guān)于Spring項(xiàng)目對(duì)JDBC的支持與基本使用詳解

    這段時(shí)間一直在觀看Spring框架,所以下面這篇文章主要給大家介紹了關(guān)于Spring項(xiàng)目對(duì)JDBC的支持與基本使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • Java NIO寫大文件對(duì)比(win7和mac)

    Java NIO寫大文件對(duì)比(win7和mac)

    這篇文章主要介紹了Java NIO寫大文件對(duì)比(win7和mac),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • mybatis的if判斷integer問題

    mybatis的if判斷integer問題

    這篇文章主要介紹了mybatis的if判斷integer問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java開發(fā)支付寶PC支付完整版

    Java開發(fā)支付寶PC支付完整版

    這篇文章主要介紹了Java開發(fā)支付寶PC支付完整版,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • Java如何獲取resources下的文件路徑和創(chuàng)建臨時(shí)文件

    Java如何獲取resources下的文件路徑和創(chuàng)建臨時(shí)文件

    這篇文章主要介紹了Java如何獲取resources下的文件路徑和創(chuàng)建臨時(shí)文件,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 最新評(píng)論