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

Spring?Boot?使用?Hutool-jwt?實(shí)現(xiàn)?token?驗(yàn)證功能

 更新時(shí)間:2023年07月04日 15:42:30   作者:訾博ZiBo  
JWT?就是一種網(wǎng)絡(luò)身份認(rèn)證和信息交換格式,這篇文章主要介紹了Spring Boot使用Hutool-jwt實(shí)現(xiàn)token驗(yàn)證,需要的朋友可以參考下

一、JWT 概述

1、簡(jiǎn)介

簡(jiǎn)單地說,JWT 就是一種網(wǎng)絡(luò)身份認(rèn)證和信息交換格式。

2、結(jié)構(gòu)

  • Header 頭部信息,主要聲明了 JWT 的簽名算法等信息;
  • Payload 載荷信息,主要承載了各種聲明并傳遞明文數(shù)據(jù);
  • Signature 簽名,擁有該部分的 JWT 被稱為 JWS,也就是簽了名的 JWS ,用于校驗(yàn)數(shù)據(jù)。
# 整體結(jié)構(gòu)
header.payload.signature

3、使用

JWT模塊的核心主要是兩個(gè)類:

  • JWT類用于鏈?zhǔn)缴?、解析或?yàn)證JWT信息。
  • JWTUtil類主要是JWT的一些工具封裝,提供更加簡(jiǎn)潔的JWT生成、解析和驗(yàn)證工作。

二、基本使用

邏輯較為簡(jiǎn)單,下面的代碼作為參考。

0、整體思路

  • 寫一個(gè)工具類封裝生成、校驗(yàn)和解析 token 的方法;
  • 在注冊(cè)和登錄時(shí)生成 token ,生成的 token 存入 redis ,下次登錄去 redis 獲取,如果存在則直接返回,反之重新生成,并存入 redis;
  • 在攔截器中校驗(yàn)和解析 token ,拿到 token 中有用的信息存入 private static final ThreadLocal<UserDto> *THREAD_LOCAL* = new ThreadLocal<>(); ,以便后續(xù)取用。

1、JWT 工具類

根據(jù)需要調(diào)整 userDto

package com.zibo.common.util;
import cn.hutool.jwt.JWT;
import com.zibo.modules.user.dto.UserDto;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
/**
 * JWT 工具類
 *
 * @author zibo
 * @date 2023/7/2 14:36
 * @slogan 慢慢學(xué),不要停。
 */
public class JWTUtility {
    /**
     * 密鑰
     */
    private static final byte[] KEY = "zibo".getBytes();
    /**
     * 過期時(shí)間(秒):7 天
     */
    public static final long EXPIRE = 7 * 24 * 60 * 60;
    private JWTUtility() {
    }
    /**
     * 根據(jù) userDto 生成 token
     *
     * @param dto    用戶信息
     * @return token
     */
    public static String generateTokenForUser(UserDto dto) {
        Map<String, Object> map = new HashMap<>();
        map.put("id", dto.getId());
        map.put("nickname", dto.getNickname());
        return generateToken(map);
    }
    /**
     * 根據(jù) map 生成 token 默認(rèn):HS265(HmacSHA256)算法
     *
     * @param map    攜帶數(shù)據(jù)
     * @return token
     */
    public static String generateToken(Map<String, Object> map) {
        JWT jwt = JWT.create();
        // 設(shè)置攜帶數(shù)據(jù)
        map.forEach(jwt::setPayload);
        // 設(shè)置密鑰
        jwt.setKey(KEY);
        // 設(shè)置過期時(shí)間
        jwt.setExpiresAt(new Date(System.currentTimeMillis() + EXPIRE * 1000));
        return jwt.sign();
    }
    /**
     * token 校驗(yàn)
     * @param token token
     * @return 是否通過校驗(yàn)
     */
    public static boolean verify (String token) {
        if (StringUtils.isBlank(token)) return false;
        return JWT.of(token).setKey(KEY).verify();
    }
    /**
     * token 校驗(yàn),并獲取 userDto
     * @param token token
     * @return userDto
     */
    public static UserDto verifyAndGetUser(String token) {
        if(!verify(token)) return null;
        // 解析數(shù)據(jù)
        JWT jwt = JWT.of(token);
        Long id = Long.valueOf(jwt.getPayload("id").toString());
        String nickname = jwt.getPayload("nickname").toString();
        // 返回用戶信息
        return new UserDto(id, nickname);
    }
}

2、在攔截器中校驗(yàn)和解析 token

package com.zibo.common.config;
import com.zibo.common.enums.AppCode;
import com.zibo.common.pojo.ApiException;
import com.zibo.common.pojo.UserHolder;
import com.zibo.common.util.JWTUtility;
import com.zibo.modules.user.dto.UserDto;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
/**
 * 自定義攔截器
 * @author Administrator
 */
@Component
@Slf4j
public class UserInterceptor implements HandlerInterceptor {
    /**
     * 進(jìn)入controller方法之前執(zhí)行。如果返回false,則不會(huì)執(zhí)行 controller 的方法
     *
     * @param request 請(qǐng)求
     * @param response 響應(yīng)
     * @param handler 處理器
     * @return 是否放行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 獲取 header 中的 Authorization 信息
        String token = request.getHeader("token");
        if (StringUtils.isNotBlank(token)) {
            UserDto dto = JWTUtility.verifyAndGetUser(token);
            if (dto != null) {
                UserHolder.setUserInfo(dto);
            } else {
                log.error("token 驗(yàn)證失??!token is {}, uri is {}", token, request.getRequestURI());
                throw new ApiException(AppCode.TOKEN_ERROR, "token 校驗(yàn)不通過!");
            }
        } else {
            log.error("token 驗(yàn)證失?。oken is {}, uri is {}", token, request.getRequestURI());
            throw new ApiException(AppCode.TOKEN_ERROR, "token 為空!");
        }
        return true;
    }
    /**
     * 響應(yīng)結(jié)束之前
     * @param request 請(qǐng)求
     * @param response 響應(yīng)
     * @param handler 處理器
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // 清理掉當(dāng)前線程中的數(shù)據(jù),防止內(nèi)存泄漏
        UserHolder.remove();
    }
}

3、在注冊(cè)和登錄時(shí)簽發(fā) token

@PostMapping("/loginOrRegister")
public UserDto loginOrRegister(@RequestBody @Validated UserDto dto) {
    // 通過手機(jī)號(hào)查詢
    UserDto byPhone = service.findByPhone(dto.getPhone());
    // 如果操作標(biāo)記為空,則報(bào)錯(cuò)
    if (ObjectUtils.isEmpty(dto.getOperation())) {
        throw new ApiException("操作標(biāo)記不能為空!");
    }
    // 如果是注冊(cè)
    if (dto.getOperation() == 0) {
        // 如果用戶已經(jīng)存在,則報(bào)錯(cuò)
        if (ObjectUtils.isNotEmpty(byPhone)) {
            throw new ApiException("注冊(cè)失??!賬號(hào)已存在!");
        }
        // 創(chuàng)建用戶
        Long save = service.save(dto);
        // 返回用戶信息
        UserDto userDto = service.findById(save);
        // 根據(jù)用戶生成 token
        String token = JWTUtility.generateTokenForUser(userDto);
        // 保存到 redis
        service.saveToken(userDto.getId(), token);
        // 設(shè)置 token
        userDto.setToken(token);
        LogUtility.baseInfoWith("注冊(cè)成功!" + userDto);
        return userDto;
    }
    // 登錄
    if (ObjectUtils.isEmpty(byPhone)) {
        log.error("登錄失敗!賬號(hào)不存在!" + dto);
        // 賬號(hào)不存在
        throw new ApiException("登錄失敗!賬號(hào)不存在!com/zibo/controller/user/UserController.java:62");
    } else {
        // 比較密碼是否一致
        if (!byPhone.getPassword().equals(dto.getPassword())) {
            throw new ApiException("登錄失?。≠~號(hào)或密碼錯(cuò)誤!");
        }
        // 更新最后登錄時(shí)間
        byPhone.setLastLoginTime(LocalDateTime.now());
        service.save(byPhone);
        // 從 redis 獲取 token
        String token = service.getToken(byPhone.getId());
        if (StringUtils.isBlank(token)) {
            // 根據(jù)用戶生成 token
            token = JWTUtility.generateTokenForUser(byPhone);
            log.info("用戶登錄,并生成token,id 為:{}, 昵稱為:{},token 為:{}", byPhone.getId(), byPhone.getNickname(), token);
            // 保存到 redis
            service.saveToken(byPhone.getId(), token);
        }
        // 設(shè)置 token
        byPhone.setToken(token);
        LogUtility.baseInfoWith("登錄成功!" + byPhone);
        return byPhone;
    }
}

4、用戶信息 UserHolder

package com.zibo.common.pojo;
import com.zibo.modules.user.dto.UserDto;
/**
 * 存放用戶信息的容器
 * @author Administrator
 */
public class UserHolder {
    private static final ThreadLocal<UserDto> THREAD_LOCAL = new ThreadLocal<>();
    private UserHolder() {
    }
    /**
     * 獲取線程中的用戶
     * @return 用戶信息
     */
    public static UserDto getUserInfo() {
        return THREAD_LOCAL.get();
    }
    /**
     * 設(shè)置當(dāng)前線程中的用戶
     * @param info 用戶信息
     */
    public static void setUserInfo(UserDto info) {
        THREAD_LOCAL.set(info);
    }
    public static Long getUserId() {
        UserDto dto = THREAD_LOCAL.get();
        if (dto != null) {
            return dto.getId();
        } else {
            // 注冊(cè)或登錄時(shí)沒有,返回 0
            return 0L;
        }
    }
    public static void remove() {
        THREAD_LOCAL.remove();
    }
}

到此這篇關(guān)于Spring Boot 使用 Hutool-jwt 實(shí)現(xiàn) token 驗(yàn)證的文章就介紹到這了,更多相關(guān)Spring Boot token 驗(yàn)證內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MyBatis映射關(guān)系詳解

    MyBatis映射關(guān)系詳解

    本文重點(diǎn)介紹MyBatis映射關(guān)系重點(diǎn)是映射關(guān)系一對(duì)一,一對(duì)一映射方式結(jié)合應(yīng)用實(shí)例給大家詳細(xì)講解,對(duì)MyBatis映射關(guān)系相關(guān)知識(shí)感興趣的朋友一起看看吧
    2022-11-11
  • HTTP 415錯(cuò)誤-Unsupported media type詳解

    HTTP 415錯(cuò)誤-Unsupported media type詳解

    這篇文章主要介紹了HTTP 415錯(cuò)誤-Unsupported media type詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Java AQS信號(hào)量Semaphore的使用

    Java AQS信號(hào)量Semaphore的使用

    Semaphore來自于JDK1.5的JUC包,直譯過來就是信號(hào)量,被作為一種多線程并發(fā)控制工具來使用。本文將詳解其原理與使用方法,感興趣的可以學(xué)習(xí)一下
    2023-02-02
  • Java過濾器與監(jiān)聽器間區(qū)別與聯(lián)系

    Java過濾器與監(jiān)聽器間區(qū)別與聯(lián)系

    監(jiān)聽器是一個(gè)接口內(nèi)容由我們實(shí)現(xiàn),會(huì)在特定時(shí)間被調(diào)用,監(jiān)聽器用于監(jiān)聽web應(yīng)用中三大域?qū)ο?request,session,application),信息的創(chuàng)建,銷毀,增加,修改,刪除等動(dòng)作的發(fā)生,然后做出相應(yīng)的響應(yīng)處理
    2023-01-01
  • Spring Cloud Config 配置中心使用指南

    Spring Cloud Config 配置中心使用指南

    Spring Cloud Config 提供了一個(gè)集中化的配置管理解決方案,支持多種配置源、動(dòng)態(tài)刷新和多環(huán)境配置,通過簡(jiǎn)單的配置和依賴添加,即可快速搭建配置中心和客戶端,感興趣的可以了解一下
    2026-03-03
  • 詳談springboot過濾器和攔截器的實(shí)現(xiàn)及區(qū)別

    詳談springboot過濾器和攔截器的實(shí)現(xiàn)及區(qū)別

    今天小編就為大家分享一篇詳談springboot過濾器和攔截器的實(shí)現(xiàn)及區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-08-08
  • 淺談JVM垃圾回收之哪些對(duì)象可以被回收

    淺談JVM垃圾回收之哪些對(duì)象可以被回收

    這篇文章主要介紹了JVM垃圾回收之哪些對(duì)象可以被回收,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • java線程本地變量ThreadLocal詳解

    java線程本地變量ThreadLocal詳解

    ThreadLocal則為每一個(gè)線程提供了一個(gè)變量副本,從而隔離了多個(gè)線程訪問數(shù)據(jù)的沖突,ThreadLocal提供了線程安全的對(duì)象封裝,下面我們就來詳細(xì)了解一下吧
    2019-06-06
  • SpringBoot中六種批量更新Mysql的方式效率對(duì)比分析

    SpringBoot中六種批量更新Mysql的方式效率對(duì)比分析

    文章比較了MySQL大數(shù)據(jù)量批量更新的多種方法,指出REPLACE INTO和ON DUPLICATE KEY效率最高但存在數(shù)據(jù)風(fēng)險(xiǎn),MyBatis-Plus分批更新較優(yōu),CASE WHEN因循環(huán)多效率較低,建議根據(jù)項(xiàng)目限制選擇合適方案并分批處理以避免SQL阻塞
    2025-07-07
  • MyBatis寫入Json字段以及Json字段轉(zhuǎn)對(duì)象示例詳解

    MyBatis寫入Json字段以及Json字段轉(zhuǎn)對(duì)象示例詳解

    這篇文章主要給大家介紹了關(guān)于MyBatis寫入Json字段以及Json字段轉(zhuǎn)對(duì)象的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-07-07

最新評(píng)論

怀宁县| 外汇| 江源县| 手机| 耒阳市| 横山县| 柳林县| 文昌市| 曲麻莱县| 沾益县| 武川县| 东山县| 桂林市| 田东县| 蒙山县| 醴陵市| 鸡西市| 交城县| 略阳县| 长白| 积石山| 兰坪| 澎湖县| 尼木县| 高陵县| 汶川县| 尚志市| 英吉沙县| 霍林郭勒市| 肥城市| 永嘉县| 蚌埠市| 凤山市| 洛浦县| 青海省| 司法| 石棉县| 新宾| 河池市| 伊春市| 昭苏县|