JWT --- 入门学习
1.常見的認證機制?
basic auth : 每次請求都會攜帶用戶的username,password,易被黑客攔截。
Cookie auth : 我們請求服務器,創(chuàng)建一個session對象,客戶端創(chuàng)建cookie對象??蛻舳嗣看卧L問,攜帶cookie對象。
(在當今,前后端分離中,通過前端服務器代理或反向代理,進行請求轉發(fā),從將cookie儲存在客戶端。)
oauth2 auth : 可以第三方登錄,但是比較麻煩下去授權服務器獲取授權碼,再拿到token,再去訪問資源服務。
token auth : 一般用戶注冊登錄之后,生成token對象分別存儲在數(shù)據(jù)庫,以及客戶端的localStore 或者 Cookie中。
?2.JWT?
jwt 全稱 JSON Web Token ,簡單來講是一個擁有json格式的Token。
簡單的理解:一種token的實現(xiàn)方式。
2.1 jwt組成
- ?Header:有令牌的類型和所使用的簽名算法,如HMAC、SHA256、RSA;使用Base64編碼組成;(Base64是一種編碼,不是一種加密過程,可以被翻譯成原來的樣子)
- Payload :有效負載,包含聲明;聲明是有關實體(通常是用戶)和其他數(shù)據(jù)的聲明,不放用戶敏感的信息,如密碼。同樣使用Base64編碼
- Signature :前面兩部分都使用Base64進行編碼,前端可以解開知道里面的信息。Signature需要使用編碼后的header和payload
- 加上我們提供的一個密鑰,使用header中指定的簽名算法(HS256)進行簽名。簽名的作用是保證JWT沒有被篡改過
2.2 jwt的優(yōu)點和驗證流程
2.2.1 優(yōu)點
1.jwt對比與傳統(tǒng)json和session不需要在服務端存儲
2.負載中包含了用戶所需要的信息,避免多次查詢數(shù)據(jù)庫
2.2.2 驗證流程
- 前端通過Web表單將自己的用戶名和密碼發(fā)送到后端的接口。該過程一般是HTTP的POST請求。建議的方式是通過SSL加密的傳輸(https協(xié)議),從而避免敏感信息被嗅探。
- 后端核對用戶名和密碼成功后,將用戶的id等其他信息作為JWT Payload(負載),將其與頭部分別進行Base64編碼拼接后簽名,形成一個JWT(Token)。
- 后端將JWT字符串作為登錄成功的返回結果返回給前端。前端可以將返回的結果保存在localStorage(瀏覽器本地緩存)或sessionStorage(session緩存)上,退出登錄時前端刪除保存的JWT即可。
- 前端在每次請求時將JWT放入HTTP的Header中的Authorization位。(解決XSS和XSRF問題)HEADER
- 后端檢查是否存在,如存在驗證JWT的有效性。例如,檢查簽名是否正確﹔檢查Token是否過期;檢查Token的接收方是否是自己(可選),驗證通過后后端使用JWT中包含的用戶信息進行其他邏輯操作,返回相應結果。
2.3?jwt快速入門
我們這里采用的jjwt實現(xiàn)。并且基于springboot項目實現(xiàn)的。
2.3.1 導入依賴
<!--JWT 依賴--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency>2.3.2?生成jwt
這將信息加密成jwt。
JwtBuilder jwtBuilder = Jwts.builder()// 聲明的標識{"jti":"8888"} 唯一的.setId("8888")// 主體,用戶{"sub":"Rose"}.setSubject("Rose")// 創(chuàng)建日期 {"iat":"" }.setIssuedAt(new Date())// 用的什么編碼.signWith(SignatureAlgorithm.HS256,"12345");// 拿到tokenString token = jwtBuilder.compact();System.out.println(token);System.out.println("---------------------");String[] split = token.split("\\.");System.out.println(Base64Codec.BASE64.decodeToString(split[0]));System.out.println(Base64Codec.BASE64.decodeToString(split[1]));// 無法解密System.out.println(Base64Codec.BASE64.decodeToString(split[2]));2.3.3?解析jwt
這個token需要自己替換成你生成的token。
String token = "eyJhbGciOiJIUzI1NiJ9." +"eyJqdGkiOiI4ODg4Iiwic3ViIjoiUm9zZSIsImlhdCI6MTY4NzIyODc0MX0." +"TiMu_sWRQxmlUtY-xh9G4G26UXYwGxID0kj6XC-iblI";// 解析token獲取負載中聲明的對象Claims claims = Jwts.parser()// 這里的簽名秘鑰.setSigningKey("12345").parseClaimsJws(token).getBody();System.out.println("id:"+claims.getId());System.out.println("subject:"+claims.getSubject());System.out.println("issuedAt:"+claims.getIssuedAt());2.3.4?jwt過期校驗
銜接上述生成和解析token代碼。
我們在jwt代碼中新加入,
long now = new Date().getTime(); // ---新增long exp = now + 60 * 1000; // 設置60s后過期 // ---新增JwtBuilder jwtBuilder = Jwts.builder()// 聲明的標識{"jti":"8888"} 唯一的.setId("8888")// 主體,用戶{"sub":"Rose"}.setSubject("Rose")// 發(fā)行日期 {"iat":"" }.setIssuedAt(new Date())// 用的什么編碼, secret 這是解密的秘鑰(!).signWith(SignatureAlgorithm.HS256,"12345")// 設置token過期時間.setExpiration(new Date(exp)); // --- 新增我們在解析token中,新加用來驗證token過期時間,和生成時間。
PS:simpleDateFormat.format() 方法,內(nèi)部沒有校驗null的邏輯,因此必須先生成jwt時,設置過期時間,否則為null,報異常。
System.out.println("----------------------");SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");System.out.println("jwt生成日期:"+simpleDateFormat.format(claims.getIssuedAt()));System.out.println("jwt過期日期:"+simpleDateFormat.format(claims.getExpiration()));System.out.println("當前日期:"+simpleDateFormat.format(new Date()));2.3.4 自定義聲明
我們可以在jwt中自定義claims,(這些信息會存入負載中)
銜接,上文。
JwtBuilder jwtBuilder = Jwts.builder()// 聲明的標識{"jti":"8888"} 唯一的.setId("8888")// 主體,用戶{"sub":"Rose"}.setSubject("Rose")// 發(fā)行日期 {"iat":"" }.setIssuedAt(new Date())// 用的什么編碼去簽名,12345 明文秘鑰(secret).signWith(SignatureAlgorithm.HS256,"12345")// 設置token過期時間.claim("role","admin"); // --- 新增// 直接傳入map對象//.addClaims(new HashMap<>())同樣,我們也可以在解析token中獲得到他。
System.out.println(claims.get("role"));總結
以上是生活随笔為你收集整理的JWT --- 入门学习的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 给初中级JAVA准备的面试题,致竞争激烈
- 下一篇: 求助修改日期