十年網(wǎng)站開發(fā)經(jīng)驗 + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊
量身定制 + 運營維護(hù)+專業(yè)推廣+無憂售后,網(wǎng)站問題一站解決
這篇文章主要講解了“密碼加密與微服務(wù)鑒權(quán)java JWT使用方法是什么”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“密碼加密與微服務(wù)鑒權(quán)java JWT使用方法是什么”吧!
成都創(chuàng)新互聯(lián)是一家從事企業(yè)網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計、成都做網(wǎng)站、外貿(mào)網(wǎng)站建設(shè)、行業(yè)門戶網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計制作的專業(yè)的建站公司,擁有經(jīng)驗豐富的網(wǎng)站建設(shè)工程師和網(wǎng)頁設(shè)計人員,具備各種規(guī)模與類型網(wǎng)站建設(shè)的實力,在網(wǎng)站建設(shè)領(lǐng)域樹立了自己獨特的設(shè)計風(fēng)格。自公司成立以來曾獨立設(shè)計制作的站點近千家。
微服務(wù)集群中的每個服務(wù),對外提供的都是Rest風(fēng)格的接口,而Rest風(fēng)格的一個最重要的規(guī)范就是:服務(wù)的無狀態(tài)性。
什么是無狀態(tài)?
1.服務(wù)端不保存任何客戶端請求者信息
2.客戶端的每次請求必須自備描述信息,通過這些信息識別客戶端身份
無狀態(tài),在微服務(wù)開放中,優(yōu)勢是?
1.客戶端請求不依賴服務(wù)端的信息,任何多次請求不需要必須訪問到同一臺服務(wù)
2.服務(wù)端的是否集群對客戶端透明
3.服務(wù)端可以任意的遷移和伸縮
4.減小服務(wù)端儲存壓力

服務(wù)器端生產(chǎn)唯一標(biāo)識(注意:最終需要進(jìn)行校驗)
方案1:UUID,數(shù)據(jù)單一,不能包含種類過多的信息。
方案2:RSA加密,數(shù)據(jù)多樣,需要使用算法,有一定的理解難度?!臼褂谩?/p>
瀏覽器儲存和自動攜帶數(shù)據(jù)
方案1:使用cookie,有很多局限性(大小,個數(shù))
方案2:請求參數(shù),get請求URL有長度限制,每一個路徑都需要處理比較麻煩。
方案3:瀏覽器localStroage存儲,請求頭攜帶?!臼褂谩?/p>

服務(wù)與服務(wù)之間共享數(shù)據(jù),采用JWT先生成數(shù)據(jù),在另一個服務(wù)中解析數(shù)據(jù),為了保證數(shù)據(jù)安全性,使用RSA對數(shù)據(jù)進(jìn)行加密。
使用RSA加密保證token數(shù)據(jù)在傳輸過程中不會被篡改
RSA:非對稱加密算法
同時生產(chǎn)一對密鑰:公鑰和私鑰
公鑰秘鑰:用于加密
私鑰秘鑰:用于解密
特點
工具類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 公鑰的字節(jié)形式
* @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 私鑰的字節(jié)形式
* @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);
}
/**
* 根據(jù)密文,生存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);
//創(chuàng)建父文件夾
if(!dest.getParentFile().exists()){
dest.getParentFile().mkdirs();
}
//創(chuàng)建需要的文件
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 {
//生產(chǎn)公鑰和私鑰
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風(fēng)格輕量級的授權(quán)和身份認(rèn)證規(guī)范,可實現(xiàn)無狀態(tài)、分布式的Web應(yīng)用授權(quán):官網(wǎng):https://jwt.io
JWT基于JSON的認(rèn)證規(guī)范。(Json Web Token)
使用JWT目的:生成數(shù)據(jù)、解析數(shù)據(jù)
pom
0.9.0 2.9.7 1.16.20 1.9.3 org.springframework.cloud spring-cloud-starter-netflix-zuul org.springframework.cloud spring-cloud-starter-netflix-eureka-client org.springframework.boot spring-boot-starter-test commons-beanutils commons-beanutils ${beanutils.version} io.jsonwebtoken jjwt ${jwt.jjwt.version} joda-time joda-time ${jwt.joda.version} org.projectlombok lombok ${lombok.version} provided
導(dǎo)入工具類
工具類: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 需要加密的數(shù)據(jù)(載荷內(nèi)容)
* @param expireMinutes 過期時間,單位:分鐘
* @param privateKey 私鑰
* @return
*/
public static String generateToken(Object data, int expireMinutes, PrivateKey privateKey) throws Exception {
//1 獲得jwt構(gòu)建對象
JwtBuilder jwtBuilder = Jwts.builder();
//2 設(shè)置數(shù)據(jù)
if( data == null ) {
throw new RuntimeException("數(shù)據(jù)不能為空");
}
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 設(shè)置過期時間
jwtBuilder.setExpiration(DateTime.now().plusMinutes(expireMinutes).toDate());
//4 設(shè)置加密
jwtBuilder.signWith(SignatureAlgorithm.RS256, privateKey);
//5 構(gòu)建
return jwtBuilder.compact();
}
/**
* 通過公鑰解析token
* @param token 需要解析的數(shù)據(jù)
* @param publicKey 公鑰
* @param beanClass 封裝的JavaBean
* @return
* @throws Exception
*/
public static T getObjectFromToken(String token, PublicKey publicKey,Class beanClass) throws Exception {
//1 獲得解析后內(nèi)容
Claims body = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token).getBody();
//2 將內(nèi)容封裝到對象JavaBean
T bean = beanClass.newInstance();
BeanInfo beanInfo = Introspector.getBeanInfo(beanClass);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
// 獲得屬性名
String name = propertyDescriptor.getName();
// 通過屬性名,獲得對應(yīng)解析的數(shù)據(jù)
Object value = body.get(name);
if(value != null) {
// 將獲得的數(shù)據(jù)封裝到對應(yīng)的JavaBean中
BeanUtils.setProperty(bean,name,value);
}
}
return bean;
}
} 時間處理工具:DateTime
//當(dāng)前時間 DateTime.now().toDate().toLocaleString() //當(dāng)前時間加5分鐘 DateTime.now().plusMinutes(5).toDate().toLocaleString() //當(dāng)前時間減5分鐘 DateTime.now().minusMinutes(5).toDate().toLocaleString()
//生成數(shù)據(jù), UserInfo --> String(加密) //JwtUtils.generateToken(數(shù)據(jù),過期時間(分鐘), 私鑰) String token = JwtUtils.generateToken(userInfo,30, RasUtils.getPrivateKey(priKeyPath)); //解析數(shù)據(jù), String(加密) --> UserInfo // JwtUtils.getObjectFromToken(加密數(shù)據(jù), 公鑰, 封裝對象.class); UserInfo userInfo = JwtUtils.getObjectFromToken(token, RasUtils.getPublicKey(pubKeyPath), UserInfo.class);
生產(chǎn)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包含三部分?jǐn)?shù)據(jù):頭部、載荷、簽名。
| 名稱 | 描述 | 組成部分 |
|---|---|---|
| 頭部(Header) | 通常頭部有兩部分信息 | 1. 聲明類型,這里是JW2. 加密算法,自定義 |
| 載荷(Payload) | 就是有效數(shù)據(jù) | 1. 用戶身份信息2. 注冊聲明 |
| 簽名(Signature) | 整個數(shù)據(jù)的認(rèn)證信息 | 一般根據(jù)前兩步的數(shù)據(jù),再加上服務(wù)的的密鑰(secret),通過加密算法生成。用于驗證整個數(shù)據(jù)完整和可靠性 |
生成的數(shù)據(jù)格式

感謝各位的閱讀,以上就是“密碼加密與微服務(wù)鑒權(quán)java JWT使用方法是什么”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對密碼加密與微服務(wù)鑒權(quán)java JWT使用方法是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!