本文你能學(xué)到什么?token的組成 token串的生成流程。 token在客戶端與服務(wù)器端的交互流程 Token的優(yōu)點(diǎn)和思考 參考代碼:核心代碼使用參考,不是全部代碼 JWT token的組成頭部(Header),格式如下: { “typ”: “JWT”, “alg”: “HS256” } 由上可知,該token使用HS256加密算法,將頭部使用Base64編碼可得到如下個(gè)格式的字符串: 有效載荷(Playload): { “iss”: “Online JWT Builder”, “iat”: 1416797419, “exp”: 1448333419, ……. “userid”:10001 } 有效載荷中存放了token的簽發(fā)者(iss)、簽發(fā)時(shí)間(iat)、過期時(shí)間(exp)等以及一些我們需要寫進(jìn)token中的信息。有效載荷也使用Base64編碼得到如下格式的字符串: 簽名(Signature): 將Header和Playload拼接生成一個(gè)字符串str=“eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyaWQiOjB9”,使用HS256算法和我們提供的密鑰(secret,服務(wù)器自己提供的一個(gè)字符串)對str進(jìn)行加密生成最終的JWT,即我們需要的令牌(token),形如:str.”簽名字符串”。 token在服務(wù)與客戶端的交互流程1:客戶端通過用戶名和密碼登錄 2:服務(wù)器驗(yàn)證用戶名和密碼,若通過,生成token返回給客戶端。 3:客戶端收到token后以后每次請求的時(shí)候都帶上這個(gè)token,相當(dāng)于一個(gè)令牌,表示我有權(quán)限訪問了 4:服務(wù)器接收(通常在攔截器中實(shí)現(xiàn))到該token,然后驗(yàn)證該token的合法性(為什么能驗(yàn)證下面說)。若該token合法,則通過請求,若token不合法或者過期,返回請求失敗。 關(guān)于Token的思考服務(wù)如何判斷這個(gè)token是否合法? 由上面token的生成可知,token中的簽名是由Header和有效載荷通過Base64編碼生成再通過加密算法HS256和密鑰最終生成簽名,這個(gè)簽名位于JWT的尾部,在服務(wù)器端同樣對返回過來的JWT的前部分再進(jìn)行一次簽名生成,然后比較這次生成的簽名與請求的JWT中的簽名是否一致,若一致說明token合法。由于生成簽名的密鑰是服務(wù)器才知道的,所以別人難以偽造。 token中能放敏感信息嗎? 不能,因?yàn)橛行лd荷是經(jīng)過Base64編碼生成的,并不是加密。所以不能存放敏感信息。 Token的優(yōu)點(diǎn)(1)相比于session,它無需保存在服務(wù)器,不占用服務(wù)器內(nèi)存開銷。 (2)無狀態(tài)、可拓展性強(qiáng):比如有3臺(tái)機(jī)器(A、B、C)組成服務(wù)器集群,若session存在機(jī)器A上,session只能保存在其中一臺(tái)服務(wù)器,此時(shí)你便不能訪問機(jī)器B、C,因?yàn)锽、C上沒有存放該Session,而使用token就能夠驗(yàn)證用戶請求合法性,并且我再加幾臺(tái)機(jī)器也沒事,所以可拓展性好就是這個(gè)意思。 (3)由(2)知,這樣做可就支持了跨域訪問。 Java實(shí)例:JWT token使用部分代碼來自互聯(lián)網(wǎng),找不到原作者了。。 編寫JWT(Java Web Token)操作類:JavaWebToken public class JavaWebToken { private static Logger log = LoggerFactory.getLogger(JavaWebToken.class); //該方法使用HS256算法和Secret:bankgl生成signKey private static Key getKeyInstance() { //We will sign our JavaWebToken with our ApiKey secret SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary('bankgl'); Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName()); return signingKey; } //使用HS256簽名算法和生成的signingKey最終的Token,claims中是有效載荷 public static String createJavaWebToken(Map claims) { return Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS256, getKeyInstance()).compact(); } //解析Token,同時(shí)也能驗(yàn)證Token,當(dāng)驗(yàn)證失敗返回null public static Map parserJavaWebToken(String jwt) { try { Map jwtClaims = Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(jwt).getBody(); return jwtClaims; } catch (Exception e) { log.error('json web token verify failed'); return null; } }}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
編寫登錄Conreoller,在服務(wù)器端給客戶返回token. public LoginStatusMessage checkUserAndPassword( @RequestParam(value='username',required=true) String username, @RequestParam(value='password',required=true) String password,User user,HttpServletRequest request) throws Exception{ User u = new User(); //登錄成功 if((u = userService.checkUsernameAndPassword(user)) != null){ Map m = new HashMap(); m.put('userid', user.getUserid()); String token = JavaWebToken.createJavaWebToken(m); System.out.println(token); LoginStatusMessage lsm = new LoginStatusMessage(); lsm.setUser(u); lsm.setToken(token); return lsm; }; //登錄失敗,返回Null return null; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
在攔截器中對請求中的Token驗(yàn)證(部分代碼,表示下意思): String token = request.getParameter('token'); if(JavaWebToken.parserJavaWebToken(token) != null){ //表示token合法 return true; }else{ //token不合法或者過期 return false; }
|