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

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

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

一、JWT 概述

1、簡介

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

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

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

3、使用

JWT模塊的核心主要是兩個類:

  • JWT類用于鏈式生成、解析或驗證JWT信息。
  • JWTUtil類主要是JWT的一些工具封裝,提供更加簡潔的JWT生成、解析和驗證工作。

二、基本使用

邏輯較為簡單,下面的代碼作為參考。

0、整體思路

  • 寫一個工具類封裝生成、校驗和解析 token 的方法;
  • 在注冊和登錄時生成 token ,生成的 token 存入 redis ,下次登錄去 redis 獲取,如果存在則直接返回,反之重新生成,并存入 redis;
  • 在攔截器中校驗和解析 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 慢慢學,不要停。
 */
public class JWTUtility {
    /**
     * 密鑰
     */
    private static final byte[] KEY = "zibo".getBytes();
    /**
     * 過期時間(秒):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 默認:HS265(HmacSHA256)算法
     *
     * @param map    攜帶數(shù)據(jù)
     * @return token
     */
    public static String generateToken(Map<String, Object> map) {
        JWT jwt = JWT.create();
        // 設置攜帶數(shù)據(jù)
        map.forEach(jwt::setPayload);
        // 設置密鑰
        jwt.setKey(KEY);
        // 設置過期時間
        jwt.setExpiresAt(new Date(System.currentTimeMillis() + EXPIRE * 1000));
        return jwt.sign();
    }
    /**
     * token 校驗
     * @param token token
     * @return 是否通過校驗
     */
    public static boolean verify (String token) {
        if (StringUtils.isBlank(token)) return false;
        return JWT.of(token).setKey(KEY).verify();
    }
    /**
     * token 校驗,并獲取 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、在攔截器中校驗和解析 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 {
    /**
     * 進入controller方法之前執(zhí)行。如果返回false,則不會執(zhí)行 controller 的方法
     *
     * @param request 請求
     * @param response 響應
     * @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 驗證失??!token is {}, uri is {}", token, request.getRequestURI());
                throw new ApiException(AppCode.TOKEN_ERROR, "token 校驗不通過!");
            }
        } else {
            log.error("token 驗證失??!token is {}, uri is {}", token, request.getRequestURI());
            throw new ApiException(AppCode.TOKEN_ERROR, "token 為空!");
        }
        return true;
    }
    /**
     * 響應結(jié)束之前
     * @param request 請求
     * @param response 響應
     * @param handler 處理器
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // 清理掉當前線程中的數(shù)據(jù),防止內(nèi)存泄漏
        UserHolder.remove();
    }
}

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

@PostMapping("/loginOrRegister")
public UserDto loginOrRegister(@RequestBody @Validated UserDto dto) {
    // 通過手機號查詢
    UserDto byPhone = service.findByPhone(dto.getPhone());
    // 如果操作標記為空,則報錯
    if (ObjectUtils.isEmpty(dto.getOperation())) {
        throw new ApiException("操作標記不能為空!");
    }
    // 如果是注冊
    if (dto.getOperation() == 0) {
        // 如果用戶已經(jīng)存在,則報錯
        if (ObjectUtils.isNotEmpty(byPhone)) {
            throw new ApiException("注冊失敗!賬號已存在!");
        }
        // 創(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);
        // 設置 token
        userDto.setToken(token);
        LogUtility.baseInfoWith("注冊成功!" + userDto);
        return userDto;
    }
    // 登錄
    if (ObjectUtils.isEmpty(byPhone)) {
        log.error("登錄失敗!賬號不存在!" + dto);
        // 賬號不存在
        throw new ApiException("登錄失?。≠~號不存在!com/zibo/controller/user/UserController.java:62");
    } else {
        // 比較密碼是否一致
        if (!byPhone.getPassword().equals(dto.getPassword())) {
            throw new ApiException("登錄失??!賬號或密碼錯誤!");
        }
        // 更新最后登錄時間
        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);
        }
        // 設置 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();
    }
    /**
     * 設置當前線程中的用戶
     * @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 {
            // 注冊或登錄時沒有,返回 0
            return 0L;
        }
    }
    public static void remove() {
        THREAD_LOCAL.remove();
    }
}

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

相關文章

  • MyBatis映射關系詳解

    MyBatis映射關系詳解

    本文重點介紹MyBatis映射關系重點是映射關系一對一,一對一映射方式結(jié)合應用實例給大家詳細講解,對MyBatis映射關系相關知識感興趣的朋友一起看看吧
    2022-11-11
  • HTTP 415錯誤-Unsupported media type詳解

    HTTP 415錯誤-Unsupported media type詳解

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

    Java AQS信號量Semaphore的使用

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

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

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

    Spring Cloud Config 配置中心使用指南

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

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

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

    淺談JVM垃圾回收之哪些對象可以被回收

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

    java線程本地變量ThreadLocal詳解

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

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

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

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

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

最新評論

南雄市| 牡丹江市| 华池县| 辽阳县| 富蕴县| 天等县| 武穴市| 和顺县| 宜州市| 德惠市| 平昌县| 洞头县| 广宗县| 泗水县| 金川县| 同心县| 辽阳市| 乐平市| 连州市| 隆子县| 阳城县| 安义县| 资源县| 黄大仙区| 济源市| 横峰县| 延川县| 玉环县| 东乡县| 芦山县| 砚山县| 西乡县| 西宁市| 镇坪县| 千阳县| 社会| 三都| 湾仔区| 思南县| 大足县| 大渡口区|