文章目錄
-
- 1.什麼是jwt
- 2.jwt能做什麼
- 3.jwt有何優勢
- 4.jwt的結構
- 5.JWT的使用
- 6.封裝工具類
- 7.整合springboot
1.什麼是jwt
JWT是JSON Web Token的簡寫,以Json形式做為web應用中的令牌,用于在各方之間安全地将資訊作為json對象傳輸,傳輸過程中可以完成資料加密、簽名等相關處理。
2.jwt能做什麼
1.授權。
2.資訊交換。
3.jwt有何優勢
傳統的session認證方式将session儲存在服務端(一般是記憶體),通過用戶端cookie的sessionid來找到對應的session實作認證。此方式有如下缺點:
1.随着認證使用者的增加,伺服器記憶體會随着增加。
2.如果session儲存在伺服器記憶體中,下次登入必須再次請求存session的伺服器才能進行認證,限制了應用的擴充能力。
3.cookie有被截獲的風險。
4.sessionid表達的資訊不豐富,不容易擴充。
jwt認證是将使用者資訊作為JWT Payload(負載),将其與頭部(header)分别進行Base64編碼拼接後簽名,形成一個jwt,格式為header.payload. signature(簽名)。
相對傳統的session認證,有如下優勢:
1.簡潔:可通過post參數或者在header中發送,資料小傳輸快。
2.自包含:負載中包含了所有使用者需要的資訊,避免多次查詢。
3.跨語言:因為是json加密的形式,基本适用任何web應用。
4.無須在服務端儲存,更适合分布式系統。
4.jwt的結構
1.标頭(header)
标頭由兩部分組成,令牌類型(預設jwt)和簽名算法 ,使用base64(可逆編碼,非加密)編成jwt的第一部分。
2.負載(payload)
包含了聲明,聲明是使用者相關實體和其它資料的聲明。同樣使用Base64編碼。
3.簽名(signature)
簽名是jwt的重點,由編碼後的标頭和負載加上密鑰再使用簽名算法(标頭中指定的算法)簽名後得出。
如果标頭中的簽名算法為a,編碼後的标頭為x,編碼後的負載為y,密鑰為z,簽名就是a(x+"."+y,z)。而整個jwt就是x.y.a(x+"."+y,z)。
值得注意的是因為負載的編碼可逆,負載裡不能存放敏感資訊。
5.JWT的使用
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLxIDO4QDNwMTM0IjMwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
6.封裝工具類
public class JWTUtils {
//密鑰
private static final String SING="[email protected]#$%";
/**
* 生成token
*/
public static String getToken(Map<String,String> map){
Calendar instance = Calendar.getInstance();
instance.add(Calendar.DATE,7); //7天過期
//建立Builder
JWTCreator.Builder builder = JWT.create();
//payload
map.forEach((k,v)->{
builder.withClaim(k,v);
});
String toekn = builder.withExpiresAt(instance.getTime())//過期時間
.sign(Algorithm.HMAC256(SING));//簽名
return toekn;
}
/**
* 驗證TOKEN
*/
public static void verify(String token){
JWT.require(Algorithm.HMAC256(SING)).build().verify(token);
}
/**
* 擷取token資訊
*/
public static DecodedJWT getTokenInfo(String token){
DecodedJWT verify = JWT.require(Algorithm.HMAC256(SING)).build().verify(token);
return verify;
}
}
7.整合springboot
以上實作了token的驗證,但是每次都要傳遞token,可以用攔截器進行優化。
建立攔截類:
/**
* JWT攔截器
*/
public class JWTInterceptor implements HandlerInterceptor {
//處理請求前調用
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws IOException {
Map<String, Object> map = new HashMap<>();
//擷取請求頭中的token
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","算法不一緻");
}catch (Exception e) {
e.printStackTrace();
map.put("msg","token無效");
}
map.put("state",false); //異常設定狀态
String json = new ObjectMapper().writeValueAsString(map); //将對象轉換為Json字元串
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(json);
return false;
}
}
建立配置類:
/**
* 攔截器配置類
*/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(new JWTInterceptor()) //攔截器
.addPathPatterns("/user/test") //攔截器的路徑
.excludePathPatterns("/user/login"); //不需要攔截的路徑
}
}