思路:每次登入前,向後端發送請求,由RSA生成一對公鑰和私鑰,用redis或者資料庫儲存使用者名對應的私鑰,擷取公鑰中的modulus和publicExponent,分别調用String#toString(int)方法,然後傳到前端,前端使用security.js加密密碼,然後進行登入,在後端使用私鑰解密,再驗證密碼的正确性。
注意:
- 每次登入都需要擷取公鑰和私鑰
- 保證每次登入時,生成的公鑰和私鑰與使用者名是對應的。
- 1.在maven項目的pom.xml中添加下面的依賴,為了引入import org.bouncycastle.jce.provider.BouncyCastleProvider;作為安全服務提供者
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.46</version>
</dependency>
-
2.RSAUtils工具類
RSAUtils源碼:https://pan.baidu.com/s/1mkd2WWg
- 3.Controller接口,為了驗證加密和解密的操作是否可行。(此接口要繞過攔截器)
/**
*
* @Title: generateRSAKey
* @Description: 生成公鑰和私鑰
* @param username
* @return
* @date 2018年2月5日 下午4:25:05
* @author p7
*/
@ResponseBody
@GetMapping(value = "/rsaKey/{username}")
public ResultBean generateRSAKey(@PathVariable String username) {
try {
// 擷取公鑰和私鑰
HashMap<String, Object> keys = RSAUtils.getKeys();
RSAPublicKey publicKey = (RSAPublicKey) keys.get("public");
RSAPrivateKey privateKey = (RSAPrivateKey) keys.get("private");
// 儲存私鑰到 redis,也可以儲存到資料庫
boolean res = redisService.set(username, privateKey);
if (!res) {
throw new BusinessLogicException("redis 儲存失敗");
}
// 将公鑰傳到前端
Map<String,String> map = new HashMap<String,String>();
// 注意傳回modulus和exponent以16為基數的BigInteger的字元串表示形式
map.put("modulus", publicKey.getModulus().toString(16));
map.put("exponent", publicKey.getPublicExponent().toString(16));
return new ResultBean(map);
} catch (NoSuchAlgorithmException e) {
return new ResultBean(ResultBean.ERROR, e.getMessage());
} catch (BusinessLogicException e) {
return new ResultBean(ResultBean.ERROR, e.getMessage());
}
}
/**
*
* @Title: checkRSAKey
* @Description: 驗證密碼
* @param username
* @param password
* @return
* @date 2018年2月5日 下午4:25:43
* @author p7
*/
@ResponseBody
@GetMapping(value = "/rsaKey/{username}/{password}")
public ResultBean checkRSAKey(@PathVariable String username, @PathVariable String password) {
Object object = redisService.get(username);
try {
// 解密
String decryptByPrivateKey = RSAUtils.decryptByPrivateKey(password, (RSAPrivateKey) object);
return new ResultBean(decryptByPrivateKey);
} catch (Exception e) {
return new ResultBean(ResultBean.ERROR, "解密失敗");
}
}
-
4.在登入頁面引入security.js
security.js:https://pan.baidu.com/s/1nxnArBN
- 5.在登入的js中對接接口。
$(document).ready(function() {
$(".loginBtn").click(function() {
var uName = $(".userName").val(); //擷取使用者名
var pWord = $(".passWord").val(); //擷取賬号
// 擷取
$.ajax({
type:"get",
url:userBasePath+"rsaKey/"+uName,
success:function(data){
console.log(data);
var pwdKey = new RSAUtils.getKeyPair(data.data.exponent,"",data.data.modulus);
var reversedPwd = pWord.split("").reverse().join("");
var encrypedPwd = RSAUtils.encryptedString(pwdKey,reversedPwd);
console.log(encrypedPwd);
$.ajax({
type:"get",
url:userBasePath+"rsaKey/"+uName+"/"+encrypedPwd,
success:function(data){
console.log(data);
},
error: function(result, status, xhr) {
}
});
},
error: function(result, status, xhr) {
}
});
}
}