Jwt客戶端存儲狀態可行性分析前端
一、前端首次訪問後臺,後臺生成token,放在http header的Authorization裏(官網推薦,可解決跨域cookie跨域問題),而且Authorization Type類型爲Bearer,將token返回給前端。java
二、後臺生成token的過程,包括給token指定加密協議好比HS56,加密類型好比「JWT」,自定義數據好比uuid,還有最重要的是記得指定一個超級複雜的密鑰,而且按期更換它,密鑰用於jwt簽名部分。還須要給jwt token指定一個合理的過時時間,這個也一樣很是重要。web
三、前端獲取token後存儲token,建議存入本地cookie。spring
四、前端再次發起後臺API接口訪問,此時須要帶上token,也是放在http header中且Authorization Type類型爲Bearer,後臺需校驗token的正確性後纔可訪問權限受限的API接口或其餘資源。apache
先添加maven依賴json
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.0</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.9</version> </dependency>
JAVA代碼案例跨域
1 package com.joyce.demo.jwt.controller; 2 3 import java.util.Date; 4 import java.util.HashMap; 5 import java.util.Iterator; 6 import java.util.Map; 7 import java.util.Map.Entry; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 import org.apache.commons.lang3.StringUtils; 11 import org.springframework.web.bind.annotation.RequestMapping; 12 import org.springframework.web.bind.annotation.RestController; 13 import io.jsonwebtoken.ExpiredJwtException; 14 import io.jsonwebtoken.Jwts; 15 import io.jsonwebtoken.MalformedJwtException; 16 import io.jsonwebtoken.SignatureAlgorithm; 17 import io.jsonwebtoken.SignatureException; 18 import io.jsonwebtoken.UnsupportedJwtException; 19 20 /** 21 * jwt 官網: https://jwt.io 22 * 23 * @author Joyce 朱文 2019/6/16 24 * 25 */ 26 @RestController 27 public class JwtController { 28 29 private static final String SECRET = "123456"; // jwt token私鑰,防止token被盜被破解 30 public static final long EXPIRATION_TIME = 1800_000L; // token的過時時間,30 分鐘 31 32 /** 33 * <pre> 34 * 步驟1:第一次訪問系統,生成token。 35 * </pre> 36 */ 37 @RequestMapping("/joyce/step1/firstAccess") 38 public String step1(HttpServletRequest request, HttpServletResponse response) { 39 40 // 把原來放在session裏的信息都放入token 41 HashMap<String, Object> tokenDataMap = new HashMap<>(); 42 tokenDataMap.put("uuid", "避免把敏感信息寫入token"); 43 tokenDataMap.put("other", "xxx"); 44 request.getCookies(); 45 46 // 指定token的過時時間:30分鐘 47 Date thisTokenExpTime = new Date(new Date().getTime() + EXPIRATION_TIME); 48 49 // 生成jwt token 50 String token = Jwts.builder().setClaims(tokenDataMap).setExpiration(thisTokenExpTime) 51 .signWith(SignatureAlgorithm.HS512, SECRET).compact(); 52 53 // 按照jwt官方說明,可把token放入header中的Authorization,而且Authorization type爲「Bearer Token」 54 response.setCharacterEncoding("UTF-8"); 55 response.setContentType("application/json; charset=utf-8"); 56 response.setHeader("Access-Control-Allow-Headers", "Origin,Content-Type,Authorization"); 57 response.setHeader("Authorization", "Bearer " + token); 58 // response.setHeader("Access-Control-Allow-Origin","*");//啓用跨域 59 // response.setHeader("Access-Control-Allow-Credentials", "true"); 60 // response.setHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,DELETE,PATCH,PUT"); 61 // response.setHeader("Access-Control-Max-Age", "3600"); 62 // response.setHeader("Access-Control-Allow-Headers", "Origin,X-Requested-With,x-requested-with,X-Custom-Header," + 63 // "Content-Type,Accept,Authorization"); 64 65 return token; 66 } 67 68 /** 69 * <pre> 70 * 步驟2:進入後續任何一個頁面 71 * 一、從Authorization header中獲取token 72 * 二、校驗token正確性,若是錯誤,返回提示信息 73 * </pre> 74 */ 75 @RequestMapping("/joyce/step2/validToken") 76 public String step2(HttpServletRequest request, HttpServletResponse response) { 77 78 // 獲取header 79 String authorization = request.getHeader("Authorization"); 80 System.out.println("authorization===== " + authorization); 81 82 // 解析token 83 String token = StringUtils.EMPTY; 84 // 若是token爲空,則返回失敗 85 if (StringUtils.isBlank(authorization)) { 86 return "error"; 87 } 88 89 try { 90 token = authorization.replaceFirst("Bearer ", StringUtils.EMPTY); 91 // 獲得自定義數據 92 Map<String, Object> tokenDataMap = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody(); 93 94 //////////////////////////////////// 取值方式一 95 // 獲取token裏payload有效負載數據 96 String uuid = (String) (tokenDataMap.get("uuid")); 97 String other = (String) (tokenDataMap.get("other")); 98 // Date generateTime = new Date((Long) tokenDataMap.get("myDate")); 99 100 //////////////////////////////////// 取值方式二 101 Iterator<Entry<String, Object>> it = tokenDataMap.entrySet().iterator(); 102 while (it.hasNext()) { 103 Entry<String, Object> entry = it.next(); 104 System.out.println("entry = " + entry.getKey() + ":" + entry.getValue()); 105 } 106 107 // 對全部的異常都須要進行業務處理 108 } catch (UnsupportedJwtException e) { // 當接收到的JWT格式/配置與應用程序指望的格式不匹配時拋出異常。例如,當應用程序須要一個加密簽名的JWS聲明時,若是解析一個無簽名的明文JWT,則會引起此異常。 109 // TODO: handle exception 110 } catch (MalformedJwtException e) { // 非正確的jwt結構 111 // TODO: handle exception 112 } catch (SignatureException e) { // 簽名錯誤 113 // TODO: handle exception 114 } catch (ExpiredJwtException e) { // token過時 115 // TODO: handle exception 116 } catch (IllegalArgumentException e) { // 傳遞非法參數 117 // TODO: handle exception 118 } 119 return "ok"; 120 } 121 122 }
end.cookie