Java如何簡(jiǎn)單快速入門(mén)JWT(token生成與驗(yàn)證)
一、Token簡(jiǎn)單介紹
簡(jiǎn)單來(lái)說(shuō),token就是一個(gè)將信息加密之后的密文,而jwt也是token的實(shí)現(xiàn)方式之一,用于服務(wù)器端進(jìn)行身份驗(yàn)證和授權(quán)訪問(wèn)控制。由于是快速入門(mén),這里簡(jiǎn)單介紹一下jwt的生成原理
jwt由三部分組成。分別是
1.Header(標(biāo)頭),一般用于指明token的類(lèi)型和加密算法
2.PayLoad(載荷),存儲(chǔ)token有效時(shí)間及各種自定義信息,如用戶名,id、發(fā)行者等
3.Signature(簽名),是用標(biāo)頭提到的算法對(duì)前兩部分進(jìn)行加密,在簽名認(rèn)證時(shí),防止止信息被修改
而Header和PayLoad最初都是json格式的鍵值對(duì),格式如下
Header:
{ "alg": "HS256", #簽名加密所用的算法 "typ": "JWT" #表名token的格式 }
PayLoad:此段json中保存了用戶的部分信息
{ "sub": "1234567890", #主題 "name": "John Doe", #用戶名 "isVIP": true, #是否為vip用戶 "exp": 1677740800 #過(guò)期時(shí)間 }
Signature:簽名,首先將Header和PayLoad的json字符串進(jìn)行Base64Url加密后,得到兩個(gè)加密后的字符串,然后把這兩個(gè)字符串由‘.’拼接起來(lái),然后再將拼接好的字符串再用之前 Header中提到的算法與一個(gè)密鑰(一般為一個(gè)字符串)進(jìn)行加密后得到一個(gè)新的字符串,最后把這個(gè)新字符串和之前使用Base64Url加密后的兩段字符串進(jìn)行連接,最終得到token字符串,然后就可以把它發(fā)送給客戶端進(jìn)行存儲(chǔ)了。
一般jwt格式token格式如下
eyJ0eXAiOiJqd3QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiam9rZXIiLCJleHAiOjE2OTQxODE2NDUsInB3ZCI6IjEyMyJ9.vDrOQp-FkmRCQBzfaZsxzkef-iNjkAuAaqvT7Ns5Ab0 #(Header).(PayLoad).(Signature)
當(dāng)然,作為快速上手jwt的文章,這里就不對(duì)jwt及token進(jìn)行更加深入的講解了,以上內(nèi)容只需要做簡(jiǎn)單了解有個(gè)映像即可,總而言之:
token就是一個(gè)在服務(wù)器端生成,包含了部分用戶信息,最后發(fā)送給客戶端進(jìn)行保管的加密字符串,當(dāng)客戶端向服務(wù)器再次發(fā)起請(qǐng)求時(shí),請(qǐng)求需攜帶token,服務(wù)器端對(duì)token進(jìn)行驗(yàn)證,以確定用戶是否有權(quán)訪問(wèn)。(以此來(lái)實(shí)現(xiàn),登錄驗(yàn)證,權(quán)限校驗(yàn),記住密碼等功能)
接下來(lái)做一個(gè)簡(jiǎn)單的代碼實(shí)現(xiàn)
二、代碼實(shí)現(xiàn)
- 導(dǎo)入相關(guān)依賴(lài)jar包(此jwt框架功能比較齊全且簡(jiǎn)單,適合初學(xué)者)
<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>4.2.1</version> </dependency>
- jwt生成
首先需要一個(gè)字符串密鑰進(jìn)行加密,這個(gè)字符串可自定義,然后提前規(guī)劃好你項(xiàng)目的jwt想要儲(chǔ)存哪些自定義信息,例如用戶名,密碼,id,等等(這里為了方便演示,這里就把用戶名以及密鑰字符串設(shè)為常量了)
package com.example.jwtdemo.Controller; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTCreator; import com.auth0.jwt.algorithms.Algorithm; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Date; import java.util.HashMap; import java.util.Map; @RestController @Controller("/") public class TestController { //用戶的用戶名 private static final String USERNAME = "admin"; //用于簽名加密的密鑰,為一個(gè)字符串(需嚴(yán)格保密) private static final String KEY = "the_key"; @GetMapping("/jwt") public String setToken() { //獲取jwt生成器 JWTCreator.Builder jwtBuilder = JWT.create(); //由于該生成器設(shè)置Header的參數(shù)為一個(gè)<String, Object>的Map, //所以我們提前準(zhǔn)備好 Map<String, Object> headers = new HashMap<>(); headers.put("typ", "jwt"); //設(shè)置token的type為jwt headers.put("alg", "hs256"); //表明加密的算法為HS256 //開(kāi)始生成token //我們將之前準(zhǔn)備好的header設(shè)置進(jìn)去 String token = jwtBuilder.withHeader(headers) //接下來(lái)為設(shè)置PayLoad,Claim中的鍵值對(duì)可自定義 //設(shè)置用戶名 .withClaim("username", USERNAME) //是否為VIP用戶 .withClaim("isVIP", true) //設(shè)置用戶id .withClaim("userId", 123) //token失效時(shí)間,這里為一天后失效 .withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24)) //設(shè)置該jwt的發(fā)行時(shí)間,一般為當(dāng)前系統(tǒng)時(shí)間 .withIssuedAt(new Date(System.currentTimeMillis())) //token的發(fā)行者(可自定義) .withIssuer("issuer") //進(jìn)行簽名,選擇加密算法,以一個(gè)字符串密鑰為參數(shù) .sign(Algorithm.HMAC256(KEY)); //token生成完畢,可以發(fā)送給客戶端了,前端可以使用 //localStorage.setItem("your_token", token)進(jìn)行存儲(chǔ),在 //下次請(qǐng)求時(shí)攜帶發(fā)送給服務(wù)器端進(jìn)行驗(yàn)證 System.out.println(token); return token; } }
最終生成的jwt
eyJ0eXAiOiJqd3QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJleHAiOjE2OTQyNzA0OTMsImlhdCI6MTY5NDE4NDA5MywiaXNWSVAiOnRydWUsInVzZXJuYW1lIjoiYWRtaW4ifQ.JiTMn2jDaUTolPXB0TCBBOwSHG1l75W2oy2isdWhQIU
PS:以上代碼中向jwt中注冊(cè)的鍵值對(duì)不是都為必須的,需按照自己的情況進(jìn)行設(shè)置
- jwt驗(yàn)證
我們從客戶端的請(qǐng)求中獲取其攜帶的token進(jìn)行驗(yàn)證,已確定其是否有權(quán)訪問(wèn)或進(jìn)行其他的業(yè)務(wù)邏輯操作
@GetMapping("/verify") public boolean verify(HttpServletRequest request) { /*從請(qǐng)求頭中獲取token(具體要看你的token放在了請(qǐng)求的哪里, 這里以放在請(qǐng)求頭舉例) */ String token = request.getHeader("token"); /*判斷token是否存在,若不存在,驗(yàn)證失敗, 并進(jìn)行驗(yàn)證失敗的邏輯操作(例如跳轉(zhuǎn)到登錄界面, 或拒絕訪問(wèn)等等)*/ if (token == null) return false; /*獲取jwt的驗(yàn)證器對(duì)象,傳入的算法參數(shù)以及密鑰字符串(KEY)必須 和加密時(shí)的相同*/ var require = JWT.require(Algorithm.HMAC256(KEY)).build(); DecodedJWT decode; try { /*開(kāi)始進(jìn)行驗(yàn)證,該函數(shù)會(huì)驗(yàn)證此token是否遭到修改, 以及是否過(guò)期,驗(yàn)證成功會(huì)生成一個(gè)解碼對(duì)象 ,如果token遭到修改或已過(guò)期就會(huì) 拋出異常,我們用try-catch抓一下*/ decode = require.verify(token); } catch (Exception e) { //拋出異常,驗(yàn)證失敗 return false; } //若驗(yàn)證成功,就可獲取其攜帶的信息進(jìn)行其他操作 //可以一次性獲取所有的自定義參數(shù),返回Map集合 Map<String, Claim> claims = decode.getClaims(); if (claims == null) return false; claims.forEach((k, v) -> System.out.println(k + " " + v.asString())); //也可以根據(jù)自定義參數(shù)的鍵值來(lái)獲取 if (!decode.getClaim("isVIP").asBoolean()) return false; System.out.println(decode.getClaim("username").asString()); //獲取發(fā)送者,沒(méi)有設(shè)置則為空 System.out.println(decode.getIssuer()); //獲取過(guò)期時(shí)間 System.out.println(decode.getExpiresAt()); //獲取主題,沒(méi)有設(shè)置則為空 System.out.println(decode.getSubject()); return true; }
總結(jié)
到此這篇關(guān)于Java如何簡(jiǎn)單快速入門(mén)JWT(token生成與驗(yàn)證)的文章就介紹到這了,更多相關(guān)JWT token生成與驗(yàn)證 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mybatis自動(dòng)創(chuàng)建表和更新表結(jié)構(gòu)
這篇文章主要介紹了Mybatis自動(dòng)創(chuàng)建表和更新表結(jié)構(gòu)的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-06-06struts1實(shí)現(xiàn)簡(jiǎn)單的登錄功能實(shí)例(附源碼)
本篇文章主要介紹了struts1實(shí)現(xiàn)簡(jiǎn)單的登錄功能實(shí)例(附源碼),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04Java獲取服務(wù)器IP及端口的方法實(shí)例分析
這篇文章主要介紹了Java獲取服務(wù)器IP及端口的方法,結(jié)合實(shí)例形式分析了java針對(duì)客戶端及服務(wù)器端各種常見(jiàn)的信息操作技巧與注意事項(xiàng),需要的朋友可以參考下2018-12-12Java簡(jiǎn)單實(shí)現(xiàn)UDP和TCP的示例
下面小編就為大家?guī)?lái)一篇Java簡(jiǎn)單實(shí)現(xiàn)UDP和TCP的示例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11java實(shí)現(xiàn)簡(jiǎn)單的爬蟲(chóng)之今日頭條
最近在學(xué)習(xí)搜索方面的東西,需要了解網(wǎng)絡(luò)爬蟲(chóng)方面的知識(shí),雖然有很多開(kāi)源的強(qiáng)大的爬蟲(chóng),但本著學(xué)習(xí)的態(tài)度,想到之前在做資訊站的時(shí)候需要用到爬蟲(chóng)來(lái)獲取一些文章,今天剛好有空就研究了一下.在網(wǎng)上看到了一個(gè)demo,使用的是Jsoup,我拿過(guò)來(lái)修改了一下,有需要的朋友可以參考2016-11-11