javascript
Springboot:JWT
文章目錄
- Springboot:JWT
- 一、JWT簡介
- 1、JWT的優(yōu)勢
- 2、JWT的結(jié)構(gòu)
- 2.1、標頭(Header)
- 2.2、有效負荷(Payload)
- 2.3、簽名(Signature)
 
 
- 二、SpringBoot整合JWT
Springboot:JWT
一、JWT簡介
JWT,是指JSON Web Token,也就指通過JSON形式作為Web應(yīng)用中的令牌,用于在各方之間安全地將信息作為JSON對象傳輸。在數(shù)據(jù)傳輸過程中還可以完成數(shù)據(jù)加密、簽名等相關(guān)處理。
1、JWT的優(yōu)勢
在JavaWeb階段,經(jīng)常使用session來存儲,以方便用來判斷用戶是否操作等等
但是這里暴露了一個問題,用session存儲需要占用服務(wù)器內(nèi)存,當用戶只有一兩個的時候沒啥問題,但是當用戶成千上萬的話,服務(wù)器就很難招架得住了。
并且這是基于cookie來實現(xiàn)的,因此數(shù)據(jù)很容易被截獲,因此不太安全
jwt相比前者,主要有以下優(yōu)勢:
- 簡潔:可以通過在HTTP中的header發(fā)送,因此數(shù)據(jù)量比較少,傳輸速度比較快
- 自包含:負載中包含了所有用戶所需的信息,避免了多次查詢數(shù)據(jù)庫
- 可跨域:jwt是以json格式家里存儲在客戶端的,因此,jwt是可以跨語言的
2、JWT的結(jié)構(gòu)
jwt的組成
- 標頭
- 有效負荷
- 簽名(重要,不可泄漏出去)
2.1、標頭(Header)
標頭通常由兩部分組成
第一個是令牌類型。一般是JWT
第二個則是所使用的簽名算法。比如HMACSHA256算法或者RSA
標頭通常是由Base64編碼組成JWT結(jié)構(gòu)的一部分,但是注意的是Base64編碼是一種編碼,而不是一種加密過程
通常標頭不需要規(guī)定
{"alg": "HS256","typ": "JWT" }2.2、有效負荷(Payload)
有效負荷是包含聲明,例如實體類有關(guān)的信息,比如說username等等,同樣的是使用Base64編碼的
{"usename": "zhangsan","admin": true }2.3、簽名(Signature)
簽名是由編碼后的標頭和有效負荷以及我們提供的一個密鑰,然后使用標頭規(guī)定的簽名算法進行簽名
因此,簽名的作用主要是保證JWT沒有被篡改過
之所以能保證JWT沒有被篡改,是因為如下過程
當后端傳輸數(shù)據(jù)給前端的時候,jwt會將標頭和有效負荷進行Base’64編碼,然后再用這兩部分得到的編碼字符串再加上自己定義的一個密鑰,再使用標頭規(guī)定的加密算法,從而得到一個簽名,假設(shè)得到的這個簽名是ABC
當這個jwt傳到前端的時候,就可以利用Base64解碼,從而獲取當中的某些數(shù)據(jù),當前端需要請求的時候,也會將這個jwt傳給后端,假設(shè)這過程中的有效負荷被篡改了,那么后端接受到這個jwt的時候就會先進行驗簽,將得到的jwt的標頭和有效負荷再加上自己的密鑰來進行加密,這時候肯定得到的不再是ABC,假設(shè)得到的是ABD,ABD與ABC一對比明顯不一樣,因此就可以判斷當中內(nèi)容被篡改了,最終拒絕訪問。
這當中也依然存在安全問題,主要是因為Base64是可以解碼的,因此我們的傳輸?shù)男畔⒁廊粫槐┞?#xff0c;jwt一般不用傳輸敏感信息。
JWT一般用來設(shè)計用戶認證和授權(quán)系統(tǒng),甚至實現(xiàn)Web應(yīng)用的單點登錄
二、SpringBoot整合JWT
<!--引入jwt--> <dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.4.0</version> </dependency> //生成Token Calendar instance = Calendar.getInstance(); instance.add(Calendar.SECOND, 90); String token = JWT.create()//生成令牌.withClaim("username", "李四")//設(shè)置自定義用戶名.withExpiresAt(instance.getTime())//設(shè)置過期時間.sign(Algorithm.HMAC256("DSADA_23#@#@$!GDFGS"));//設(shè)置簽名 保密 復(fù)雜 System.out.println(token);//輸出令牌像這樣生成Token可以寫成一個JWTUtils,增加代碼的復(fù)用性
public class JWTUtils {//定義自己的密鑰private static String TOKEN = "token!DASD(#$dsad%$#.";/*** 生成token* @param map 傳入的有效負荷* @return*/public static String genToken(Map<String, String> map){JWTCreator.Builder builder = JWT.create();map.forEach((k,v)->{builder.withClaim(k, v);});Calendar instance = Calendar.getInstance();//定義過期時間instance.add(Calendar.DATE, 7);builder.withExpiresAt(instance.getTime());return builder.sign(Algorithm.HMAC256(TOKEN)).toString();}/*** 驗證獲取token中的有效負載,驗證失敗返回null* @param token* @return*/public static DecodedJWT getToken(String token){return JWT.require(Algorithm.HMAC256(TOKEN)).build().verify(token);} }為了使得不用在每一個controller前端控制器都寫一遍獲取token,然后驗簽的操作
可以將這個操作寫在過濾器中,這樣的話將token放在請求體中請求,可以簡化不少操作
public class JWTInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {Map<String, Object> map = new HashMap<>();//獲取請求頭中令牌String token = request.getHeader("token");try {JWTUtils.verify(token);//驗證令牌return true;//放行請求} catch (SignatureVerificationException e) {e.printStackTrace();map.put("msg","無效簽名!");}catch (TokenExpiredException e){e.printStackTrace();map.put("msg","token過期!");}catch (AlgorithmMismatchException e){e.printStackTrace();map.put("msg","token算法不一致!");}catch (Exception e){e.printStackTrace();map.put("msg","token無效!!");}map.put("state",false);//設(shè)置狀態(tài)//將map 專為json jacksonString json = new ObjectMapper().writeValueAsString(map);response.setContentType("application/json;charset=UTF-8");response.getWriter().println(json);return false;} }配置過濾器
@Configuration public class InterceptorConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new JWTInterceptor())//其他接口token驗證.addPathPatterns("/user/test") //所有用戶都放心.excludePathPatterns("/user/login"); } }編寫前端控制器controller
package com.baizhi.controller;import com.auth0.jwt.exceptions.AlgorithmMismatchException; import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.exceptions.TokenExpiredException; import com.auth0.jwt.interfaces.DecodedJWT; import com.baizhi.entity.User; import com.baizhi.service.UserService; import com.baizhi.utils.JWTUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map;@RestController @Slf4j public class UserController {@Autowiredprivate UserService userService;@GetMapping("/user/login")public Map<String,Object> login(User user){log.info("用戶名: [{}]",user.getName());log.info("密碼: [{}]",user.getPassword());Map<String, Object> map = new HashMap<>();try{User userDB = userService.login(user);Map<String,String> payload = new HashMap<>();payload.put("id",userDB.getId());payload.put("name",userDB.getName());//生成JWT的令牌String token = JWTUtils.getToken(payload);map.put("state",true);map.put("msg","認證成功");map.put("token",token);//響應(yīng)token}catch (Exception e){map.put("state",false);map.put("msg",e.getMessage());}return map;}@PostMapping("/user/test")public Map<String,Object> test(HttpServletRequest request){Map<String, Object> map = new HashMap<>();//處理自己業(yè)務(wù)邏輯String token = request.getHeader("token");DecodedJWT verify = JWTUtils.verify(token);log.info("用戶id: [{}]",verify.getClaim("id").asString());log.info("用戶name: [{}]",verify.getClaim("name").asString());map.put("state",true);map.put("msg","請求成功!");return map;}}注意token會作為參數(shù)傳給前端
總結(jié)
以上是生活随笔為你收集整理的Springboot:JWT的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: linux小红帽
- 下一篇: 有了雀巢智能咖啡机,单身狗离“秀恩爱”还
