您好,登錄后才能下訂單哦!
這篇文章主要講解了“密碼加密與微服務鑒權java JWT使用方法是什么”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“密碼加密與微服務鑒權java JWT使用方法是什么”吧!
微服務集群中的每個服務,對外提供的都是Rest風格的接口,而Rest風格的一個最重要的規范就是:服務的無狀態性。
什么是無狀態?
1.服務端不保存任何客戶端請求者信息
2.客戶端的每次請求必須自備描述信息,通過這些信息識別客戶端身份
無狀態,在微服務開放中,優勢是?
1.客戶端請求不依賴服務端的信息,任何多次請求不需要必須訪問到同一臺服務
2.服務端的是否集群對客戶端透明
3.服務端可以任意的遷移和伸縮
4.減小服務端儲存壓力
服務器端生產唯一標識(注意:最終需要進行校驗)
方案1:UUID,數據單一,不能包含種類過多的信息。
方案2:RSA加密,數據多樣,需要使用算法,有一定的理解難度。【使用】
瀏覽器儲存和自動攜帶數據
方案1:使用cookie,有很多局限性(大小,個數)
方案2:請求參數,get請求URL有長度限制,每一個路徑都需要處理比較麻煩。
方案3:瀏覽器localStroage存儲,請求頭攜帶。【使用】
服務與服務之間共享數據,采用JWT先生成數據,在另一個服務中解析數據,為了保證數據安全性,使用RSA對數據進行加密。
使用RSA加密保證token數據在傳輸過程中不會被篡改
RSA:非對稱加密算法
同時生產一對密鑰:公鑰和私鑰
公鑰秘鑰:用于加密
私鑰秘鑰:用于解密
特點
工具類RasUtils
package com.czxy.utils; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.security.*; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; /** * @author 庭前云落 * @Date 2019/12/13 22:01 * @description */ public class RasUtils { /** * 從文件中讀取公鑰 * * @param filename 公鑰保存路徑,相對于classpath * @return 公鑰對象 * @throws Exception */ public static PublicKey getPublicKey(String filename) throws Exception { byte[] bytes = readFile(filename); return getPublicKey(bytes); } /** * 從文件中讀取密鑰 * * @param filename 私鑰保存路徑,相對于classpath * @return 私鑰對象 * @throws Exception */ public static PrivateKey getPrivateKey(String filename) throws Exception { byte[] bytes = readFile(filename); return getPrivateKey(bytes); } /** * 獲取公鑰 * * @param bytes 公鑰的字節形式 * @return * @throws Exception */ public static PublicKey getPublicKey(byte[] bytes) throws Exception { X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes); KeyFactory factory = KeyFactory.getInstance("RSA"); return factory.generatePublic(spec); } /** * 獲取密鑰 * * @param bytes 私鑰的字節形式 * @return * @throws Exception */ public static PrivateKey getPrivateKey(byte[] bytes) throws Exception { PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes); KeyFactory factory = KeyFactory.getInstance("RSA"); return factory.generatePrivate(spec); } /** * 根據密文,生存rsa公鑰和私鑰,并寫入指定文件 * * @param publicKeyFilename 公鑰文件路徑 * @param privateKeyFilename 私鑰文件路徑 * @param secret 生成密鑰的密文 * @throws Exception */ public static void generateKey(String publicKeyFilename, String privateKeyFilename, String secret) throws Exception { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); SecureRandom secureRandom = new SecureRandom(secret.getBytes()); keyPairGenerator.initialize(1024, secureRandom); KeyPair keyPair = keyPairGenerator.genKeyPair(); // 獲取公鑰并寫出 byte[] publicKeyBytes = keyPair.getPublic().getEncoded(); writeFile(publicKeyFilename, publicKeyBytes); // 獲取私鑰并寫出 byte[] privateKeyBytes = keyPair.getPrivate().getEncoded(); writeFile(privateKeyFilename, privateKeyBytes); } private static byte[] readFile(String fileName) throws Exception { return Files.readAllBytes(new File(fileName).toPath()); } private static void writeFile(String destPath, byte[] bytes) throws IOException { File dest = new File(destPath); //創建父文件夾 if(!dest.getParentFile().exists()){ dest.getParentFile().mkdirs(); } //創建需要的文件 if (!dest.exists()) { dest.createNewFile(); } Files.write(dest.toPath(), bytes); } }
//生成公鑰和私鑰 RasUtils.generateKey(公鑰位置,私鑰位置,密碼); RasUtils.generateKey(pubKeyPath,priKeyPath,"234"); //獲得公鑰 RasUtils.getPublicKey(pubKeyPath); //獲得私鑰 RasUtils.getPrivateKey(priKeyPath);
package com.czxy; import com.czxy.utils.RasUtils; import org.junit.Test; import java.security.PrivateKey; import java.security.PublicKey; /** * @author 庭前云落 * @Date 2019/12/13 22:07 * @description */ public class TestRAS { private static final String pugbKeyPath="D:\\ras\\ras.pub"; private static final String priKeyPath="D:\\ras\\ras.pri"; @Test public void testRas() throws Exception { //生產公鑰和私鑰 RasUtils.generateKey(pugbKeyPath,priKeyPath,"234"); } @Test public void testGetRas() throws Exception { //獲得公鑰和私鑰 PublicKey publicKey = RasUtils.getPublicKey(pugbKeyPath); PrivateKey privateKey = RasUtils.getPrivateKey(priKeyPath); System.out.println(publicKey.toString()); System.out.println(privateKey.toString()); } }
JWT,全稱是JSON Web Token,是JSON風格輕量級的授權和身份認證規范,可實現無狀態、分布式的Web應用授權:官網:https://jwt.io
JWT基于JSON的認證規范。(Json Web Token)
使用JWT目的:生成數據、解析數據
pom
<properties> <jwt.jjwt.version>0.9.0</jwt.jjwt.version> <jwt.joda.version>2.9.7</jwt.joda.version> <lombok.version>1.16.20</lombok.version> <beanutils.version>1.9.3</beanutils.version> </properties> <dependencies> <!--網關依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> <!--添加eureka客戶端--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!--測試--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <!--jwt依賴--> <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>${beanutils.version}</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>${jwt.jjwt.version}</version> </dependency> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>${jwt.joda.version}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> <scope>provided</scope> </dependency> </dependencies>
導入工具類
工具類:JwtUtils
package com.czxy.utils; import io.jsonwebtoken.Claims; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.apache.commons.beanutils.BeanUtils; import org.joda.time.DateTime; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.security.PrivateKey; import java.security.PublicKey; /** * @author 庭前云落 * @Date 2019/12/13 22:01 * @description */ public class JwtUtils { /** * 私鑰加密token * @param data 需要加密的數據(載荷內容) * @param expireMinutes 過期時間,單位:分鐘 * @param privateKey 私鑰 * @return */ public static String generateToken(Object data, int expireMinutes, PrivateKey privateKey) throws Exception { //1 獲得jwt構建對象 JwtBuilder jwtBuilder = Jwts.builder(); //2 設置數據 if( data == null ) { throw new RuntimeException("數據不能為空"); } BeanInfo beanInfo = Introspector.getBeanInfo(data.getClass()); PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { // 獲得屬性名 String name = propertyDescriptor.getName(); // 獲得屬性值 Object value = propertyDescriptor.getReadMethod().invoke(data); if(value != null) { jwtBuilder.claim(name,value); } } //3 設置過期時間 jwtBuilder.setExpiration(DateTime.now().plusMinutes(expireMinutes).toDate()); //4 設置加密 jwtBuilder.signWith(SignatureAlgorithm.RS256, privateKey); //5 構建 return jwtBuilder.compact(); } /** * 通過公鑰解析token * @param token 需要解析的數據 * @param publicKey 公鑰 * @param beanClass 封裝的JavaBean * @return * @throws Exception */ public static <T> T getObjectFromToken(String token, PublicKey publicKey,Class<T> beanClass) throws Exception { //1 獲得解析后內容 Claims body = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token).getBody(); //2 將內容封裝到對象JavaBean T bean = beanClass.newInstance(); BeanInfo beanInfo = Introspector.getBeanInfo(beanClass); PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { // 獲得屬性名 String name = propertyDescriptor.getName(); // 通過屬性名,獲得對應解析的數據 Object value = body.get(name); if(value != null) { // 將獲得的數據封裝到對應的JavaBean中 BeanUtils.setProperty(bean,name,value); } } return bean; } }
時間處理工具:DateTime
//當前時間 DateTime.now().toDate().toLocaleString() //當前時間加5分鐘 DateTime.now().plusMinutes(5).toDate().toLocaleString() //當前時間減5分鐘 DateTime.now().minusMinutes(5).toDate().toLocaleString()
//生成數據, UserInfo --> String(加密) //JwtUtils.generateToken(數據,過期時間(分鐘), 私鑰) String token = JwtUtils.generateToken(userInfo,30, RasUtils.getPrivateKey(priKeyPath)); //解析數據, String(加密) --> UserInfo // JwtUtils.getObjectFromToken(加密數據, 公鑰, 封裝對象.class); UserInfo userInfo = JwtUtils.getObjectFromToken(token, RasUtils.getPublicKey(pubKeyPath), UserInfo.class);
生產Token
package com.czxy; import com.czxy.utils.RasUtils; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.joda.time.DateTime; import org.junit.Test; /** * @author 庭前云落 * @Date 2019/12/13 22:32 * @description */ public class TestJWT { private static final String pugbKeyPath="D:\\ras\\ras.pub"; private static final String priKeyPath="D:\\ras\\ras.pri"; @Test public void testGenerateToken() throws Exception { String str = Jwts.builder() .claim("test","庭前云落") .setExpiration(DateTime.now().plusMinutes(60).toDate()) .signWith(SignatureAlgorithm.RS256, RasUtils.getPrivateKey(priKeyPath)) .compact(); System.out.println(str); } }
"庭前云落":Token ---》eyJhbGciOiJSUzI1NiJ9.eyJ0ZXN0Ijoi5bqt5YmN5LqR6JC9IiwiZXhwIjoxNTc2MjkzMTEyfQ.a32GamgbG6F1xC-4NtEJNNLX8mcV6Ycyc2bf7_7wX6_xa4LzimqO5ZH9d4bSii-IixYudSreurJ2Rjq72aXvv3nv_VsZasmODeLkBMLtBGhKDztKW3hNQM7rcRLIxL4PFP48xjosJl48F-hXSgEWqYXuC6Voexlk8W4eonRcGqg
解析Token
@Test public void testParseToken() throws Exception { String token="\n" + "eyJhbGciOiJSUzI1NiJ9.eyJ0ZXN0Ijoi5bqt5YmN5LqR6JC9IiwiZXhwIjoxNTc2MjkzMTEyfQ.a32GamgbG6F1xC-4NtEJNNLX8mcV6Ycyc2bf7_7wX6_xa4LzimqO5ZH9d4bSii-IixYudSreurJ2Rjq72aXvv3nv_VsZasmODeLkBMLtBGhKDztKW3hNQM7rcRLIxL4PFP48xjosJl48F-hXSgEWqYXuC6Voexlk8W4eonRcGqg"; Claims claims = Jwts.parser().setSigningKey(RasUtils.getPublicKey(pubKeyPath)). parseClaimsJws(token).getBody(); String text = claims.get("test",String.class); System.out.println(text); }
編寫測試對象UserInfo
package com.czxy.domain; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @author 庭前云落 * @Date 2019/12/13 21:55 * @description */ @Data @AllArgsConstructor @NoArgsConstructor public class UserInfo { private Long id; private String username; }
測試
package com.czxy; import com.czxy.domain.UserInfo; import com.czxy.utils.JwtUtils; import com.czxy.utils.RasUtils; import org.junit.Test; /** * @author 庭前云落 * @Date 2019/12/13 22:32 * @description */ public class TestJWT { private static final String pubKeyPath="D:\\ras\\ras.pub"; private static final String priKeyPath="D:\\ras\\ras.pri"; @Test public void testToken() throws Exception { UserInfo userInfo = new UserInfo(); userInfo.setId(10L); userInfo.setUsername("庭前云落"); String token = JwtUtils.generateToken(userInfo, 30, RasUtils.getPrivateKey(priKeyPath)); System.out.println(token); } @Test public void testParserToken() throws Exception { String token="eyJhbGciOiJSUzI1NiJ9.eyJjbGFzcyI6ImNvbS5jenh6LmRvbWFpbi5Vc2VySW5mbyIsImlkIjoxMCwidXNlcm5hbWUiOiLluq3liY3kupHokL0iLCJleHAiOjE1NzYyOTI1Mzd9.LlyCCBeW4f7fjU3LmE7cA8W7aNB1BXp23Yv9WQJouCRCtoD46GiXQAHn2kezuzuPfp2u5G0OXOIeahHtnvRMSDjtQFJ6s-cZcKNupJPOPK8BzuEnladx0ilcrSr5TeWNxujg-svSz5EJRwWj8KbRKhQluohpAg0VhERjJjD5wTY"; UserInfo userInfo = JwtUtils.getObjectFromToken(token, RasUtils.getPublicKey(pubKeyPath), UserInfo.class); System.out.println(userInfo); } }
JWT的token包含三部分數據:頭部、載荷、簽名。
名稱 | 描述 | 組成部分 |
---|---|---|
頭部(Header) | 通常頭部有兩部分信息 | 1. 聲明類型,這里是JW2. 加密算法,自定義 |
載荷(Payload) | 就是有效數據 | 1. 用戶身份信息2. 注冊聲明 |
簽名(Signature) | 整個數據的認證信息 | 一般根據前兩步的數據,再加上服務的的密鑰(secret),通過加密算法生成。用于驗證整個數據完整和可靠性 |
生成的數據格式
感謝各位的閱讀,以上就是“密碼加密與微服務鑒權java JWT使用方法是什么”的內容了,經過本文的學習后,相信大家對密碼加密與微服務鑒權java JWT使用方法是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。