Vue開發(fā)中Jwt的使用詳解
一.Jwt的簡介
JWT(JSON Web Token)是一種用于身份驗證和授權(quán)的開放標(biāo)準(zhǔn),它定義了一種緊湊且自包含的方式來在各方之間安全地傳輸信息。JWT通常由三部分組成:頭部、負(fù)載和簽名。其中,頭部描述了JWT的元數(shù)據(jù),如加密算法、類型等,負(fù)載包含了需要傳遞的信息,比如用戶ID、權(quán)限等,簽名則用于保證數(shù)據(jù)的完整性和安全性。
JWT的工作流程通常如下:
- 用戶通過用戶名和密碼進(jìn)行校驗,服務(wù)器驗證通過后生成JWT;
- 瀏覽器將JWT存儲在客戶端,可以使用cookie或localStorage等機制;
- 客戶端每次向服務(wù)器發(fā)送請求時,都會附加JWT到HTTP請求頭中;
- 服務(wù)器收到請求后,會驗證JWT的合法性、解析出負(fù)載中的信息,并對請求作出相應(yīng)的處理。
使用JWT的優(yōu)點包括:
- 無狀態(tài):每個請求都包含了足夠的信息,無需在服務(wù)端保存任何狀態(tài);
- 可擴展性:可以添加額外的信息到負(fù)載中,如用戶角色、過期時間等;
- 自包含:負(fù)載中包含了信息和簽名,可以驗證數(shù)據(jù)的完整性和來源;
- 通用性:JWT是一種通用的協(xié)議,可以被不同的應(yīng)用和語言使用。
需要注意的是,在使用JWT進(jìn)行身份驗證時,為保證數(shù)據(jù)的安全性,需要遵循一些最佳實踐,如使用HTTPS協(xié)議傳輸、設(shè)置合適的過期時間等。此外,JWT僅適用于傳遞數(shù)據(jù),而不適用于加密數(shù)據(jù),如果需要加密數(shù)據(jù),需要添加額外的加密層級。
總之,JWT是一種輕量級的身份驗證和授權(quán)協(xié)議,具有無狀態(tài)、可擴展、自包含和通用等優(yōu)點,被廣泛應(yīng)用于Web和移動應(yīng)用程序中。
傳統(tǒng)開發(fā)的弊端,以及解決方法
二.Jwt工具類的使用
1.定義工具類
package com.zking.ssm.jwt; import java.util.Date; import java.util.Map; import java.util.UUID; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; import io.jsonwebtoken.Claims; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; /** * JWT驗證過濾器:配置順序 CorsFilte->JwtUtilsr-->StrutsPrepareAndExecuteFilter * */ public class JwtUtils { /** * JWT_WEB_TTL:WEBAPP應(yīng)用中token的有效時間,默認(rèn)30分鐘 */ public static final long JWT_WEB_TTL = 30 * 60 * 1000; /** * 將jwt令牌保存到header中的key */ public static final String JWT_HEADER_KEY = "jwt"; // 指定簽名的時候使用的簽名算法,也就是header那部分,jwt已經(jīng)將這部分內(nèi)容封裝好了。 private static final SignatureAlgorithm SIGNATURE_ALGORITHM = SignatureAlgorithm.HS256; private static final String JWT_SECRET = "f356cdce935c42328ad2001d7e9552a3";// JWT密匙 private static final SecretKey JWT_KEY;// 使用JWT密匙生成的加密key static { byte[] encodedKey = Base64.decodeBase64(JWT_SECRET); JWT_KEY = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES"); } private JwtUtils() { } /** * 解密jwt,獲得所有聲明(包括標(biāo)準(zhǔn)和私有聲明) * * @param jwt * @return * @throws Exception */ public static Claims parseJwt(String jwt) { Claims claims = Jwts.parser() .setSigningKey(JWT_KEY) .parseClaimsJws(jwt) .getBody(); return claims; } /** * 創(chuàng)建JWT令牌,簽發(fā)時間為當(dāng)前時間 * * @param claims * 創(chuàng)建payload的私有聲明(根據(jù)特定的業(yè)務(wù)需要添加,如果要拿這個做驗證,一般是需要和jwt的接收方提前溝通好驗證方式的) * @param ttlMillis * JWT的有效時間(單位毫秒),當(dāng)前時間+有效時間=過期時間 * @return jwt令牌 */ public static String createJwt(Map<String, Object> claims, long ttlMillis) { // 生成JWT的時間,即簽發(fā)時間 2021-10-30 10:02:00 -> 30 10:32:00 long nowMillis = System.currentTimeMillis(); //鏈?zhǔn)秸Z法: // 下面就是在為payload添加各種標(biāo)準(zhǔn)聲明和私有聲明了 // 這里其實就是new一個JwtBuilder,設(shè)置jwt的body JwtBuilder builder = Jwts.builder() // 如果有私有聲明,一定要先設(shè)置這個自己創(chuàng)建的私有的聲明,這個是給builder的claim賦值,一旦寫在標(biāo)準(zhǔn)的聲明賦值之后,就是覆蓋了那些標(biāo)準(zhǔn)的聲明的 .setClaims(claims) // 設(shè)置jti(JWT ID):是JWT的唯一標(biāo)識,根據(jù)業(yè)務(wù)需要,這個可以設(shè)置為一個不重復(fù)的值,主要用來作為一次性token,從而回避重放攻擊。 // 可以在未登陸前作為身份標(biāo)識使用 .setId(UUID.randomUUID().toString().replace("-", "")) // iss(Issuser)簽發(fā)者,寫死 .setIssuer("zking") // iat: jwt的簽發(fā)時間 .setIssuedAt(new Date(nowMillis)) // 代表這個JWT的主體,即它的所有人,這個是一個json格式的字符串,可放數(shù)據(jù){"uid":"zs"}。此處沒放 // .setSubject("{}") // 設(shè)置簽名使用的簽名算法和簽名使用的秘鑰 .signWith(SIGNATURE_ALGORITHM, JWT_KEY) // 設(shè)置JWT的過期時間 .setExpiration(new Date(nowMillis + ttlMillis)); return builder.compact(); } /** * 復(fù)制jwt,并重新設(shè)置簽發(fā)時間(為當(dāng)前時間)和失效時間 * * @param jwt * 被復(fù)制的jwt令牌 * @param ttlMillis * jwt的有效時間(單位毫秒),當(dāng)前時間+有效時間=過期時間 * @return */ public static String copyJwt(String jwt, Long ttlMillis) { //解密JWT,獲取所有的聲明(私有和標(biāo)準(zhǔn)) //old Claims claims = parseJwt(jwt); // 生成JWT的時間,即簽發(fā)時間 long nowMillis = System.currentTimeMillis(); // 下面就是在為payload添加各種標(biāo)準(zhǔn)聲明和私有聲明了 // 這里其實就是new一個JwtBuilder,設(shè)置jwt的body JwtBuilder builder = Jwts.builder() // 如果有私有聲明,一定要先設(shè)置這個自己創(chuàng)建的私有的聲明,這個是給builder的claim賦值,一旦寫在標(biāo)準(zhǔn)的聲明賦值之后,就是覆蓋了那些標(biāo)準(zhǔn)的聲明的 .setClaims(claims) // 設(shè)置jti(JWT ID):是JWT的唯一標(biāo)識,根據(jù)業(yè)務(wù)需要,這個可以設(shè)置為一個不重復(fù)的值,主要用來作為一次性token,從而回避重放攻擊。 // 可以在未登陸前作為身份標(biāo)識使用 //.setId(UUID.randomUUID().toString().replace("-", "")) // iss(Issuser)簽發(fā)者,寫死 // .setIssuer("zking") // iat: jwt的簽發(fā)時間 .setIssuedAt(new Date(nowMillis)) // 代表這個JWT的主體,即它的所有人,這個是一個json格式的字符串,可放數(shù)據(jù){"uid":"zs"}。此處沒放 // .setSubject("{}") // 設(shè)置簽名使用的簽名算法和簽名使用的秘鑰 .signWith(SIGNATURE_ALGORITHM, JWT_KEY) // 設(shè)置JWT的過期時間 .setExpiration(new Date(nowMillis + ttlMillis)); return builder.compact(); } }
2.通過工具類進(jìn)行測試
2.1生成jwt
public void test1() {// 生成JWT //JWT Token=Header.Payload.Signature //頭部.載荷.簽名 //Payload=標(biāo)準(zhǔn)聲明+私有聲明+公有聲明 //定義私有聲明 Map<String, Object> claims = new HashMap<String, Object>(); claims.put("username", "lb"); claims.put("age", 18); //TTL:Time To Live String jwt = JwtUtils.createJwt(claims, JwtUtils.JWT_WEB_TTL); System.out.println(jwt); //獲取Payload(包含標(biāo)準(zhǔn)和私有聲明) Claims parseJwt = JwtUtils.parseJwt(jwt); for (Map.Entry<String, Object> entry : parseJwt.entrySet()) { System.out.println(entry.getKey() + "=" + entry.getValue()); } Date d1 = parseJwt.getIssuedAt(); Date d2 = parseJwt.getExpiration(); System.out.println("令牌簽發(fā)時間:" + sdf.format(d1)); System.out.println("令牌過期時間:" + sdf.format(d2)); }
2.2解析舊的Jwt
@Test public void test2() {// 解析oldJwt //io.jsonwebtoken.ExpiredJwtException:JWT過期異常 //io.jsonwebtoken.SignatureException:簽名異常 //String oldJwt="eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1OTA3MTg2NzcsImlhdCI6MTU5MDcxNjg3NywiYWdlIjoxOCwianRpIjoiNDFmZjFiZGFkYzkxNDA3OGE4ZGUyNGRkZDEwYjU4N2IiLCJ1c2VybmFtZSI6InpzcyJ9.DdPvioX6kuhV6lEfD9QAN2eQSk_mO3dYkmDmTQsqa78"; //eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MzU1NjE3MjcsImlhdCI6MTYzNTU1OTkyNywiYWdlIjoxOCwianRpIjoiN2RlYmIzM2JiZTg3NDBmODgzNDI5Njk0ZWE4NzcyMTgiLCJ1c2VybmFtZSI6InpzcyJ9.dUR-9JUlyRdoYx-506SxXQ3gbHFCv0g5Zm8ZGzK1fzw String newJwt="eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ6a2luZyIsImV4cCI6MTY2MjM0Njg3MSwiaWF0IjoxNjYyMzQ1MDcxLCJhZ2UiOjE4LCJqdGkiOiI4YjllNzc3YzFlMDM0MjViYThmMDVjNTFlMTU3NDQ1MiIsInVzZXJuYW1lIjoienNzIn0.UWpJxPxwJ09PKxE2SY5ME41W1Kv3jP5bZGKK-oNUDuM"; String oldJwt = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MzU1NjE3MjcsImlhdCI6MTYzNTU1OTkyNywiYWdlIjoxOCwianRpIjoiN2RlYmIzM2JiZTg3NDBmODgzNDI5Njk0ZWE4NzcyMTgiLCJ1c2VybmFtZSI6InpzcyJ9.dUR-9JUlyRdoYx-506SxXQ3gbHFCv0g5Zm8ZGzK1fzw"; Claims parseJwt = JwtUtils.parseJwt(newJwt); for (Map.Entry<String, Object> entry : parseJwt.entrySet()) { System.out.println(entry.getKey() + "=" + entry.getValue()); } Date d1 = parseJwt.getIssuedAt(); Date d2 = parseJwt.getExpiration(); System.out.println("令牌簽發(fā)時間:" + sdf.format(d1)); System.out.println("令牌過期時間:" + sdf.format(d2)); }
2.3測試JWT的有效時間
@Test public void test4() {// 測試JWT的有效時間 Map<String, Object> claims = new HashMap<String, Object>(); claims.put("username", "zss"); String jwt = JwtUtils.createJwt(claims, 3 * 1000L); System.out.println(jwt); Claims parseJwt = JwtUtils.parseJwt(jwt); Date d1 = parseJwt.getIssuedAt(); Date d2 = parseJwt.getExpiration(); System.out.println("令牌簽發(fā)時間:" + sdf.format(d1)); System.out.println("令牌過期時間:" + sdf.format(d2)); }
2.4復(fù)制Jwt
@Test public void test3() {// 復(fù)制jwt,并延時30分鐘 String oldJwt = "eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ6a2luZyIsImV4cCI6MTY2MjM0Njg3MSwiaWF0IjoxNjYyMzQ1MDcxLCJhZ2UiOjE4LCJqdGkiOiI4YjllNzc3YzFlMDM0MjViYThmMDVjNTFlMTU3NDQ1MiIsInVzZXJuYW1lIjoienNzIn0.UWpJxPxwJ09PKxE2SY5ME41W1Kv3jP5bZGKK-oNUDuM"; //String newJwt = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MDU3NTM2NTUsImlhdCI6MTYwNTc1MTg1NSwiYWdlIjoxOCwianRpIjoiYmNmN2Q1MzQ2YjE3NGU2MDk1MmIxYzQ3ZTlmMzQyZjgiLCJ1c2VybmFtZSI6InpzcyJ9.m1Qn84RxgbKCnsvrdbbAnj8l_5Jwovry8En0j4kCxhc"; //String oldJwt = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NjI5MDMzNjAsImlhdCI6MTU2MjkwMTU2MCwiYWdlIjoxOCwianRpIjoiZDVjMzE4Njg0MDcyNDgyZDg1MDE5ODVmMDY3OGQ4NjkiLCJ1c2VybmFtZSI6InpzcyJ9.XDDDRRq5jYq5EdEBHtPm7GcuBz4S0VhDTS1amRCdf48"; String newJwt = JwtUtils.copyJwt(oldJwt, JwtUtils.JWT_WEB_TTL); System.out.println(newJwt); Claims parseJwt = JwtUtils.parseJwt(newJwt); for (Map.Entry<String, Object> entry : parseJwt.entrySet()) { System.out.println(entry.getKey() + "=" + entry.getValue()); } Date d1 = parseJwt.getIssuedAt(); Date d2 = parseJwt.getExpiration(); System.out.println("令牌簽發(fā)時間:" + sdf.format(d1)); System.out.println("令牌過期時間:" + sdf.format(d2)); }
3.實例
3.1打開Jwt校驗
3.2 實現(xiàn)效果
定義jwt變量(state.js)
設(shè)置值(muntionis.js)
setJwt:(state,payload)=>{ //state 就是 state.js文件導(dǎo)出的參數(shù) // payload vue 傳遞的參數(shù) state.jwt=payload.jwt; }
getters.js取值
getJwt:(state)=>{ return state.jwt; }
在Http.js設(shè)置攔截請求
// 請求攔截器 axios.interceptors.request.use(function(config) { let jwt= window.vm.$store.getters.getJwt; if(jwt){ config.headers['jwt'] = jwt; } return config; }, function(error) { return Promise.reject(error); }); // 響應(yīng)攔截器 axios.interceptors.response.use(function(response) { let jwt = response.headers['jwt']; if(jwt){ window.vm.$store.commit('setJwt', { jwt:jwt }); } return response; }, function(error) { return Promise.reject(error); });
3.3效果展示
到此這篇關(guān)于Vue開發(fā)中Jwt的使用詳解的文章就介紹到這了,更多相關(guān)Vue Jwt內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一個vue組件庫發(fā)布到npm的完整實現(xiàn)過程
工作的時候總是使用別人的npm包,然而我有時心底會好奇自己如何發(fā)布一個npm包呢,什么時候自己的包能夠被很多人喜歡并使用呢,下面這篇文章主要給大家介紹了關(guān)于一個vue組件庫發(fā)布到npm的相關(guān)資料,需要的朋友可以參考下2022-03-03vue-cli使用stimulsoft.reports.js的詳細(xì)教程
Stimulsoft?Reports.JS是一個使用JavaScript和HTML5生成報表的平臺。它擁有所有擁來設(shè)計,編輯和查看報表的必需組件。該報表工具根據(jù)開發(fā)人員數(shù)量授權(quán)而不是根據(jù)應(yīng)用程序的用戶數(shù)量。接下來通過本文給大家介紹vue-cli使用stimulsoft.reports.js的方法,一起看看吧2021-12-12Vue3+Element?Plus實現(xiàn)el-table跨行顯示(非腳手架)
這篇文章主要介紹了Vue3+Element Plus實現(xiàn)el-table跨行顯示(非腳手架),本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-09-09