欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot如何集成Token

 更新時間:2025年01月06日 15:00:35   作者:愛JAVA的少年閏土  
文章介紹了如何使用jjwt插件實現(xiàn)Token的生成和校驗,該插件可以直接與SpringBoot集成,Token由三部分組成,分別是header、payload和signature,通過在請求頭中傳遞Token,后端可以驗證其合法性,從而提高安全性

SpringBoot集成Token

簡介

在項目開發(fā)中,Token 是常見且重要的一個功能,目前對于 Token 設(shè)計有很多成熟的方案;

比如使用 Redis 存儲管理 Token,不過這種方式需要而額外集成 Redis 服務(wù),雖然 Redis 查詢效率很高,但是對于普通項目來說,還是增加了開發(fā)難度;

本章將介紹一個簡單易用的 Token 插件:jjwt,該插件直接與 SpringBoot 集成即可,其原理是:在服務(wù)端加密生成一個三段式加密字符串,前端每次請求都要將該 Token 傳遞給服務(wù)端(建議放在 Header 中),后臺通過解析該 Token 字符串,判斷其是否合法,超時等

基本原理

從這個架構(gòu)圖中可以看出 JWT 主體分為 3 個部分:user,application server,authentication server;

非常常見的一個架構(gòu),首先用戶需要 通過登錄等手段向 authentication server 發(fā)送一個認(rèn)證請求,authentication會返回給用戶一個 JWT (這個JWT 的具體內(nèi)容格式是啥后面會說,先理解成一個簡單的字符串好了)

此后用戶向application server發(fā)送的所有請求都要捎帶上這個 JWT,然后application server 會驗證這個 JWT 的合法性,驗證通過則說明用戶請求時來自合法守信的客戶端

JWT 結(jié)構(gòu)

這個 JWT 的格式,就是一個由三部分組成的字符串:header.payload.signatue;

其中 header 主要包含了加密算法等信息;

payload 則主要包含后端服務(wù)器放入的自定義信息,如:登錄用戶的信息;signature 就是使用算法生成的能夠?qū)崿F(xiàn)身份認(rèn)證的字符串

實現(xiàn)步驟

1. 在項目的 pom.xml 配置文件中添加如下依賴

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.7.0</version>
</dependency>

2. 添加一個公共類 Token,提供生成 Token,校驗等基本方法

/**
 * @ClassName Token
 * @Author Andy
 * @Date 2020/7/14 14:32
 * @Description 用于生成, 解析 token 的工具類
 **/
public class Token {
    // 密鑰
    private static SecretKeySpec key = "";

    // 對密鑰加密
    static {
        key = new SecretKeySpec(Constant.SECRET_KEY.getBytes(), SignatureAlgorithm.HS512.getJcaName());
    }

    // 生成 token
    public static String createToken(String subject, Map < String, Object > claims, Date expireDate) {
        JwtBuilder builder = Jwts.builder()
            .setClaims(claims) // payload 私有申明,存放一些個人信息,必須放在第一個
            .setIssuer(Constant.AUTHOR) // token 的簽發(fā)人
            .setIssuedAt(new Date()) // token 的簽發(fā)時間
            .setSubject(subject) // token 的所有人, 一般放用戶的 id 之類的
            .setExpiration(expireDate) // 過期時間
            .signWith(SignatureAlgorithm.HS512, key); // token 的簽名算法
        return builder.compact();
    }

    // 生成 token
    public static String createToken(String subject, Date expireDate) {
        return createToken(subject, new HashMap < > (), expireDate);
    }

    // 解析 token
    public static Claims parseToken(String token) {
        try {
            return Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody();
        } catch (Exception e) {
            throw new CommonException(Exceptions.TOKEN_PARSE_ERROR);
        }
    }

    // 將 token 標(biāo)記為過期
    public static void markTokenExpired(String token) {
        Date expireDate = CommonUtil.currentTimeAddSeconds(1);
        Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody().setExpiration(expireDate);
    }

    // 判斷 token 是否過期
    public static boolean checkTokenExpired(String token) {
        Claims claims = parseToken(token);
        return !CommonUtil.checkExpired(claims.getExpiration());
    }

    // 獲取 token 的 subject 信息, 登錄成功保存的時用戶的主鍵
    public static String getSubject(HttpServletRequest request) {
        return parseToken(getToken(request)).getSubject();
    }
   
    // 根據(jù) token 獲取 subject 信息
    public static String getSubject(String token) {
        return parseToken(token).getSubject();
    }

    // 根據(jù) HttpServletRequest 獲取 token
    public static String getToken(HttpServletRequest request) {
        return request.getHeader(Constant.HEADER_TOKEN);
    }

    // 獲取 token 的簽發(fā)人
    public static String getIssuer(String token) {
        return parseToken(token).getIssuer();
    }
}

這里使用到其它關(guān)聯(lián)類的方法或?qū)傩匀缦?/p>

  • Constant.class
// token 簽發(fā)者
public static final String AUTHOR = "duzimei";
// 獲取 header 中 token 標(biāo)識
public static final String HEADER_TOKEN = "token";
// token 密鑰加密字符串(取自 《肖申克的救贖》經(jīng)典臺詞)
public static final String SECRET_KEY = "Fear can hold you prisoner.Hope can set you free";
// 設(shè)置 token 的過期時間為 1 個小時(單位秒)
public static final Integer EXPIRE_DATE = 3600;
  • CommonUtil.class
// 在當(dāng)前時間基礎(chǔ)上加 seconds 秒
public static Date currentTimeAddSeconds(int seconds) {
    Calendar now = Calendar.getInstance();
    now.add(Calendar.SECOND, seconds);
    return now.getTime();
}

// 判斷于當(dāng)前日期是否過期
public static boolean checkExpired(Date expiration) {
    return expiration.after(new Date());
}

異常定義請忽略,根據(jù)自己項目而實現(xiàn)

3. 定義一個 UserController.class,添加登錄方法,當(dāng)用戶登錄成功后,返回一個 Token

@RestController
@RequestMapping("/user")
public class User {    
    @Autowired
    private UserService userService;

    @PostMapping("/login")
    public Map<Integer, String> login(@RequestBody JSONObject params) {
        Map<Integer, String> result = new HashMap<>();
        String userAccount = params.getString("account");
        String password = params.getString("password");
        User tempUser = userService.getUserByAccount(userAccount);
        if(null == tempUser) {
            result.put(-1, "用戶不存在");
        } else if(!password.equals(tempUser.getPassword())) {
            result.put("-2", "密碼不正確");
        } else {
            // 用戶登錄成功, 添加 token 返回給客戶端
            // 1. 設(shè)置 token 過期時間
            Date expireDate = CommonUtil.currentTimeAddSeconds(Contant.EXPIRE_DATE);
            // 2. 這里我們把用戶的 id 信息放到 subject 中
            String token = Token.createToken(tempUser.getUserId(), expireDate); 
            result.put(0, token);
        }
        return result;
    }
}

4. 前端當(dāng)用戶登錄成功后,向后臺發(fā)送其它請求的時候,將 Token 放到 Header 中一起傳送給后臺

$.ajax({
    headers: {
        "token": 從后臺獲取到的token
    },
    url: "http://xxx:8080/user/info",
    method: "GET",
    data: null,
    dataType: "json",
    contentType: "application/json",
    success: function(data) {
        console.log(data);
    },
    error: function(x, s, e) {
        console.log("異常信息: " + x.responseText);
    }
})

5.解析Token

在后臺對應(yīng)方法中,就可以通過解析 Token 獲取用戶 id,判斷請求是否合法;

像下面這種請求,前端根本不用傳遞用戶的 id 到后臺,后臺通過解析 Token,獲取 Token 的 subject 屬性就能拿到用戶 id,在一定程度上提高了安全性

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/info")
    public Map<Integer, Object> getUserInfo(HttpServletRequest request) {
        Map<Integer, Object> result = new HashMap<>();
        String token = Token.getToken(request);
        // 對 token 進(jìn)行校驗
        if(StringUtils.isEmpty(token)) { // 如果沒有獲取到 Token
            result.put(-1, "沒有獲取到 Token, 請求被阻止"); 
        } else if(!Constant.AUTHOR.equals(Token.getIssuer(token))) { // 如果 Token 的簽發(fā)人不正確
            result.put(-2, "非法的 Token, 請求被阻止");
        } else if(Token.checkTokenExpired(token)) { // 如果 Token 已過期
            result.put(-3, "過期的 Token, 請求被阻止");
        } else {
            String userId = Token.getSubject(token);
            User user = userService.getUserById(userId);
            result.put(0, user);
        }
        return result;
    }
}

這里只是介紹的關(guān)于 JWT 實現(xiàn) Token 的簡單用法,在實際開發(fā)過程中,建議使用 Spring 的 AOP 技術(shù)實現(xiàn)對 Token 的校驗;

我們這里只是實現(xiàn)了一個最簡單的 Token,這 Token 中還可以放入其它信息,由于是單向加密的,所以數(shù)據(jù)傳輸非常安全;

更進(jìn)一步的實現(xiàn),應(yīng)根據(jù)實際開發(fā)具體實現(xiàn)

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Maven訪問倉庫順序代碼實例解析

    Maven訪問倉庫順序代碼實例解析

    這篇文章主要介紹了Maven訪問倉庫順序?qū)嵗馕?文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-08-08
  • springboot項目配置logback-spring.xml實現(xiàn)按日期歸檔日志的方法

    springboot項目配置logback-spring.xml實現(xiàn)按日期歸檔日志的方法

    本文主要介紹了springboot項目配置logback-spring.xml實現(xiàn)按日期歸檔日志的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-08-08
  • Springboot使用Redis中ZSetOperations實現(xiàn)博客訪問量

    Springboot使用Redis中ZSetOperations實現(xiàn)博客訪問量

    在日常的網(wǎng)站使用中,經(jīng)常會碰到頁面的訪問量,本文主要介紹了Springboot使用Redis中ZSetOperations實現(xiàn)博客訪問量,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • SpringCache 分布式緩存的實現(xiàn)方法(規(guī)避redis解鎖的問題)

    SpringCache 分布式緩存的實現(xiàn)方法(規(guī)避redis解鎖的問題)

    這篇文章主要介紹了SpringCache 分布式緩存的實現(xiàn)方法(規(guī)避redis解鎖的問題),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • PowerJob的QueryConvertUtils工作流程源碼解讀

    PowerJob的QueryConvertUtils工作流程源碼解讀

    這篇文章主要為大家介紹了PowerJob的QueryConvertUtils工作流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • IDEA:Git stash 暫存分支修改的實現(xiàn)代碼

    IDEA:Git stash 暫存分支修改的實現(xiàn)代碼

    這篇文章主要介紹了IDEA:Git stash 暫存分支修改的實現(xiàn)代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-03-03
  • SpringBoot使用ResponseBodyEmitter處理流式日志和進(jìn)度條

    SpringBoot使用ResponseBodyEmitter處理流式日志和進(jìn)度條

    這篇文章主要為大家詳細(xì)介紹了SpringBoot如何使用ResponseBodyEmitter處理流式日志和進(jìn)度條,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-02-02
  • SpringMvc @Valid如何拋出攔截異常

    SpringMvc @Valid如何拋出攔截異常

    這篇文章主要介紹了SpringMvc @Valid如何拋出攔截異常,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-09-09
  • Arrays.asList方法總結(jié)

    Arrays.asList方法總結(jié)

    本文主要對Arrays.asList方法進(jìn)行總結(jié)。具有很好的參考價值,下面跟著小編一起來看下吧
    2017-02-02
  • Java面試題沖刺第二十六天--實戰(zhàn)編程

    Java面試題沖刺第二十六天--實戰(zhàn)編程

    這篇文章主要為大家分享了最有價值的三道java實戰(zhàn)面試題,涵蓋內(nèi)容全面,包括數(shù)據(jù)結(jié)構(gòu)和算法相關(guān)的題目、經(jīng)典面試編程題等,感興趣的小伙伴們可以參考一下
    2021-08-08

最新評論