1. 程式人生 > >JWT的生成及驗證過程

JWT的生成及驗證過程

在前後端分離的場景中,前後臺主要用jwt互動,比如說前端發一個提交資訊的請求,後臺必須知道這個提交者的資訊吧(提交者id),但為了使傳輸更安全,jwt包含了需要的使用者資訊以加密的方式傳輸以達到這個目的。

先看看jwt的定義,網上隨處可見的:jwt全稱Json Web Token,由三部分構成:頭部(header)、載荷(payload, )、簽證(signature).

傳輸資訊用到的就是載荷:就是存放有效資訊的地方,就是這樣的鍵值對構成的Map物件:

iss: jwt簽發者
sub: jwt所面向的使用者
aud: 接收jwt的一方
exp: jwt的過期時間,這個過期時間必須要大於簽發時間
nbf: 定義在什麼時間之前,該jwt都是不可用的.
iat: jwt的簽發時間
jti: jwt的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊。
jwt用Claims物件來存自定義的資訊(也是一個鍵值對的Map物件):當登入的時候,就把當前的使用者的資訊存進去,這裡模擬一下(假如從資料庫中獲取了使用者資訊)
@ResponseBody
@RequestMapping("login.do")
public JsonAndModel sayHello(HttpServletRequest request, HttpServletResponse response) {
    Map<String,Object> claims = new HashMap<>();
    claims.put("username","wang");
    claims.put("userid",12);
    System.out.println(new Date().getTime() + "---start---");
    return JsonAndModel.builder(TokenUtil.tokens(claims)).build();
}
然後把資訊存到一個map裡面,通過工具生成token字串返回給前臺,當前臺再次請求的時候就帶上這個token,然後取引數驗證。
package cn.wzy.util;
 
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.*;
 
/**
 * @author wzy
 * @Date 2018/4/6 14:00
 */
public class TokenUtil {
    private static Properties properties = new Properties();
    private static ResourceBundle resource = ResourceBundle.getBundle("database");
    public static Object getValue(String key) {
        return resource.getString(key);
    }
 
    public static String tokens(Map<String,Object> claims) {
        String SecretKey = (String) getValue("secretkey");
        //獲取當前的時間
        Calendar calendar = Calendar.getInstance();
        Date date = new Date(System.currentTimeMillis());
        calendar.setTime(date);
        //向後退後的秒數
        int time = Integer.parseInt((String) getValue("millisecond"));
        calendar.add(Calendar.MILLISECOND, time);
        Date endTime = calendar.getTime();
        String issuer = (String) getValue("JWT_ISSUER");
        String aud = (String) getValue("JWT_AUD");
        JwtBuilder builder = Jwts.builder().setClaims(claims)
                .signWith(SignatureAlgorithm.HS256,SecretKey)
                .setClaims(claims)
                .setSubject((String)claims.get("username"))
                .setIssuedAt(new Date())
                .setExpiration(endTime)
                .setIssuer(issuer)
                .setAudience(aud);
        return builder.compact();
    }
 
    /**
     * 從jwt中獲取使用者資訊
     * @param jsonWebToken
     * @return
     */
    public static Claims parseJWT(String jsonWebToken) {
        String secretKey = (String) getValue("secretkey");
        try {
            Claims claims = Jwts.parser()
                    .setSigningKey(secretKey)
                    .parseClaimsJws(jsonWebToken).getBody();
            return claims;
        } catch (Exception ex) {
            return null;
        }
    }
}
驗證過程:把前端存到header裡面的token解析成一個Claims物件獲取引數驗證(當時間過了設定的token失效時間,這個物件就失效為null,也就未登入)
@ResponseBody
@RequestMapping("checkOnlie.do")
public JsonAndModel check(HttpServletRequest request, HttpServletResponse response) {
    String claims = request.getHeader("claims");
    Claims info = null;
    if (claims != null) {
        info = TokenUtil.parseJWT(claims);
        System.out.println(info == null);
        System.out.println(new Date().getTime());
    }
    return JsonAndModel.builder(info).build();
}