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

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)證失??!token 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)文章

  • 如何利用java實(shí)現(xiàn)生成PDF文件

    如何利用java實(shí)現(xiàn)生成PDF文件

    前段時(shí)間因?yàn)橄嚓P(guān)業(yè)務(wù)需求需要后臺(tái)生成pdf文件,下面這篇文章主要給大家介紹了關(guān)于如何利用java實(shí)現(xiàn)生成PDF文件的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-10-10
  • Java中使用Jedis操作Redis的示例代碼

    Java中使用Jedis操作Redis的示例代碼

    本篇文章主要介紹了Java中使用Jedis操作Redis的示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下。
    2016-12-12
  • Java實(shí)現(xiàn)多用戶注冊(cè)登錄的幸運(yùn)抽獎(jiǎng)

    Java實(shí)現(xiàn)多用戶注冊(cè)登錄的幸運(yùn)抽獎(jiǎng)

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)多用戶注冊(cè)登錄的幸運(yùn)抽獎(jiǎng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • Java對(duì)線程池做監(jiān)控的實(shí)現(xiàn)方法

    Java對(duì)線程池做監(jiān)控的實(shí)現(xiàn)方法

    本文主要介紹了Java對(duì)線程池做監(jiān)控的實(shí)現(xiàn)方法,監(jiān)控線程池可以幫助我們了解線程池的狀態(tài),如當(dāng)前活躍線程數(shù)、任務(wù)隊(duì)列長(zhǎng)度、已完成任務(wù)數(shù)等,下面就一起來了解一下
    2024-07-07
  • SpringBoot統(tǒng)一返回JSON格式實(shí)現(xiàn)方法詳解

    SpringBoot統(tǒng)一返回JSON格式實(shí)現(xiàn)方法詳解

    這篇文章主要介紹了SpringBoot統(tǒng)一返回JSON格式實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2023-02-02
  • JavaWeb三大組件之一的Filter詳解

    JavaWeb三大組件之一的Filter詳解

    本篇文章主要介紹了JavaWeb三大組件之中的Filter過濾器詳解,實(shí)例分析了JavaWeb之Filter過濾器的使用技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2022-06-06
  • mybatis處理枚舉類的簡(jiǎn)單方法

    mybatis處理枚舉類的簡(jiǎn)單方法

    這篇文章主要給大家介紹了關(guān)于mybatis處理枚舉類的簡(jiǎn)單方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用mybatis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • Quarkus中實(shí)現(xiàn)Resteasy的文件上傳下載操作

    Quarkus中實(shí)現(xiàn)Resteasy的文件上傳下載操作

    這篇文章主要為大家介紹了Quarkus中實(shí)現(xiàn)Resteasy的文件上傳下載的操作過程步驟,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-02-02
  • java動(dòng)態(tài)代理示例分享

    java動(dòng)態(tài)代理示例分享

    這篇文章主要介紹了java動(dòng)態(tài)代理示例,需要的朋友可以參考下
    2014-02-02
  • java中阻塞隊(duì)列和非阻塞隊(duì)列的實(shí)現(xiàn)

    java中阻塞隊(duì)列和非阻塞隊(duì)列的實(shí)現(xiàn)

    在Java并發(fā)編程中,阻塞隊(duì)列和非阻塞隊(duì)列是兩種主要的隊(duì)列類型,分別適用于不同的場(chǎng)景,了解這兩種隊(duì)列的特點(diǎn)和工作機(jī)制,可以幫助開發(fā)者更好地選擇合適的數(shù)據(jù)結(jié)構(gòu)解決并發(fā)問題
    2024-10-10

最新評(píng)論