您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“SpringBoot整合JWT的介紹以及用法”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“SpringBoot整合JWT的介紹以及用法”吧!
1.JWT
2.JWT登錄執(zhí)行流程圖
3.為什么使用JWT?
4.JWT的組成
5.SpringBoot整合JWT
測試
總結(jié)
JWT(JSON Web Token),為了在網(wǎng)絡(luò)應(yīng)用環(huán)境間傳遞聲明而執(zhí)行的一種基于JSON的開放標(biāo)準(zhǔn)。將用戶信息加密到token中,服務(wù)器不保存任何用戶信息,服務(wù)器通過保存的密鑰驗證token的正確性。
優(yōu)點
1.簡介:可以通過 URL POST 參數(shù)或者在 HTTP header 發(fā)送,因為數(shù)據(jù)量小,傳輸速度也很快;
2.自包含:負(fù)載中可以包含用戶所需要的信息,避免了多次查詢數(shù)據(jù)庫;
3.因為 Token 是以 JSON 加密的形式保存在客戶端的,所以 JWT 是跨語言的,原則上任何 web 形式都支持;
4.不需要再服務(wù)端保存會話信息,特別適用于分布式微服務(wù);
缺點
1.無法作廢已經(jīng)發(fā)布的令牌;
2.不易應(yīng)對數(shù)據(jù)過期;
在傳統(tǒng)的用戶登錄認(rèn)證中,因為http是無狀態(tài)的,所以都是采用session+cokokie,用戶登錄成功,服務(wù)端會保存一個session,并給客戶端一個sessionId,客戶端會把sessionId保存在cookie中,每次請求都會攜帶sessionId。cookie+session模式是保存在內(nèi)存中,在分布式服務(wù)中會面臨session共享問題,隨著用戶量得增加,開銷就越來越大。而JWT不需要在服務(wù)端保存會話信息,特別適合分布式微服務(wù)。
簡潔:可以用過URL,POST參數(shù)或者在HTTP Header發(fā)送,因為數(shù)據(jù)量小,傳輸速度也快
JWT支持跨語言
自包含: 載荷中包含了所有用戶所需要的信息,避免了多次查詢數(shù)據(jù)庫。
JWT由三部分構(gòu)成,類似于如下:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJscyIsImV4cCI6MTYyNDU5Nzc5Nn0.4kwT1elZCb_k2D7AxbuFHM35VmBK4PcmLaqHhcHEq4_wVe8GVO8ODypGSKksTs-hraBopBCm2IC9EC2rO-GHng
第一部分為頭部(header),承載兩部分信息
聲明類型(JWT)
聲明加密算法,默認(rèn)為HMAC SHA256
{ "typ","JWT", "alg","HS256" }
使用Base64加密后
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9
第二部分為payload(載荷),存放有效信息的地方,這些有效信息分為三部分:
標(biāo)準(zhǔn)中注冊的聲明
公共的聲明
私有的聲明
其中,標(biāo)準(zhǔn)中注冊的聲明 (建議但不強(qiáng)制使用)包括如下幾個部分 :
iss: jwt簽發(fā)者;
sub: jwt所面向的用戶;
aud: 接收jwt的一方;
exp: jwt的過期時間,這個過期時間必須要大于簽發(fā)時間;
nbf: 定義在什么時間之前,該jwt都是不可用的;
iat: jwt的簽發(fā)時間;
jwt的唯一身份標(biāo)識,主要用來作為一次性token,從而回避重放攻擊
公共的聲明部分:
公共的聲明可以添加任何信息,一般添加用戶的相關(guān)信息或其他業(yè)務(wù)需要的必要信息,但不建議添加銘感信息,因為在客戶端可解密。
私有的聲明部分:
私有的聲明是提供者和消費(fèi)者共同定義的聲明,不建議存放敏感信息,因為base64是對稱解密的,意味著該部分信息可以歸類為明文信息。
第三部分為signature(簽證)
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload); //密鑰就是我們定義的secret,加密后得到簽證 var signature = HMACSHA256(encodedString, '密鑰');
引入依賴
<!--JWT--> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.7.0</version> </dependency> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.4.0</version> </dependency> <!--StringUtils工具包--> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> <!--ConfigurationProperties出現(xiàn)異常--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
配置application.yml文件
server: port: 8888 spring: jwt: #過期時間 expireTime: 1800000 #加密密鑰 secret: lsyyp5201314 #token返回頭部 header: LOGINTOKEN
JWT工具類
package org.best.util; import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.TokenExpiredException; import org.springframework.boot.context.properties.ConfigurationProperties; import java.util.Date; @ConfigurationProperties(prefix = "spring.jwt") public class JWTUtils { public static String header; private static String secret; private static String expireTime; /** * 生成token * @param sub 用戶唯一信息 * @return token */ public static String createToken(String sub){ return JWT .create() .withSubject(sub) .withExpiresAt(new Date(System.currentTimeMillis()+Long.parseLong(expireTime))) .sign(Algorithm.HMAC512(secret)); } /** * 根據(jù)token獲取用戶信息 * @param token * @return 用戶信息 */ public static String validateToken(String token){ return JWT .require(Algorithm.HMAC512(secret)) .build() .verify(token) .getSubject(); } /** * 檢驗Token是否需要刷新 * @param token * @return */ public static boolean refreshToken(String token) { Date expireDate = null; try { expireDate = JWT .require(Algorithm.HMAC512(secret)) .build() .verify(token) .getExpiresAt(); } catch (TokenExpiredException e) { return true; } return (expireDate.getTime()-System.currentTimeMillis())<0; } public void setHeader(String header) { this.header = header; } public String getSecret() { return secret; } public void setSecret(String secret) { this.secret = secret; } public String getExpireTime() { return expireTime; } public void setExpireTime(String expireTime) { this.expireTime = expireTime; } }
自定義攔截器
package org.best.config; import org.apache.commons.lang.StringUtils; import org.best.common.TokenIsNullException; import org.best.common.TokenValidateException; import org.best.util.JWTUtils; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String logintoken = request.getHeader("LOGINTOKEN"); //如果token為空 if (StringUtils.isBlank(logintoken)){ throw new TokenIsNullException("請登錄"); } //校驗Token String sub = JWTUtils.validateToken(logintoken); if (StringUtils.isBlank(sub)){ throw new TokenValidateException("token校驗失敗"); } //更新token有效期(生產(chǎn)新token) if (JWTUtils.refreshToken(logintoken)){ String token = JWTUtils.createToken(sub); response.setHeader(JWTUtils.header,token); } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
注冊攔截器
package org.best.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class MyWebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry .addInterceptor(new LoginInterceptor()) .addPathPatterns("/find") .excludePathPatterns("/login"); } }
自定義異常
package org.best.common; /** * Token校驗異常 */ public class TokenValidateException extends RuntimeException { public TokenValidateException() { } public TokenValidateException(String message) { super(message); } }
package org.best.common; /** * Token為空異常 */ public class TokenIsNullException extends RuntimeException{ public TokenIsNullException() { } public TokenIsNullException(String message) { super(message); } }
自定義Controller
package org.best.controller; import org.best.pojo.User; import org.best.util.JWTUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletResponse; @RestController public class LoginController { @GetMapping("/login") public String login(User user, HttpServletResponse response){ //這里就不做數(shù)據(jù)庫查詢了 //根據(jù)用戶id生成token String token = JWTUtils.createToken(String.valueOf(user.getId())); //將token存入HTTP響應(yīng)頭中 response.setHeader(JWTUtils.header,token); return user.toString(); } @GetMapping("/find") public String find(){ return "success"; } }
登錄接口
我們來測試下find 接口 ,不帶token會出現(xiàn)啥情況
帶上token
到此,相信大家對“SpringBoot整合JWT的介紹以及用法”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。