后台代码
1、引入依赖
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.60</version>
</dependency>
2、新建生成公钥和解密数据的工具类
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.interfaces.RSAPublicKey;
import javax.crypto.Cipher;
import org.apache.commons.codec.binary.Base64;
public class RSAUtils {
//KeyPair is a simple holder for a key pair.
private static final KeyPair keyPair = initKey();
/**
* 初始化方法,产生key pair,提供provider和random
* @return KeyPair instance
*/
private static KeyPair initKey() {
try {
//添加provider
Provider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
Security.addProvider(provider);
//产生用于安全加密的随机数
SecureRandom random = new SecureRandom();
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", provider);
generator.initialize(1024, random);
return generator.generateKeyPair();
} catch(Exception e) {
throw new RuntimeException(e);
}
}
/**
* 产生public key
* @return public key字符串
*/
public static String generateBase64PublicKey() {
PublicKey publicKey = (RSAPublicKey)keyPair.getPublic();
//encodeBase64(): Encodes binary data using the base64
//algorithm but does not chunk the output.
//getEncoded():返回key的原始编码形式
return new String(Base64.encodeBase64(publicKey.getEncoded()));
}
/**
* 解密数据
* @param string 需要解密的字符串
* @return 破解之后的字符串
*/
public static String decryptBase64(String string) {
//decodeBase64():将Base64数据解码为"八位字节”数据
return new String(decrypt(Base64.decodeBase64(string.getBytes())));
}
private static byte[] decrypt(byte[] byteArray) {
try {
Provider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
Security.addProvider(provider);
//Cipher: 提供加密和解密功能的实例
//transformation: "algorithm/mode/padding"
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider);
PrivateKey privateKey = keyPair.getPrivate();
//初始化
cipher.init(Cipher.DECRYPT_MODE, privateKey);
//doFinal(): 加密或者解密数据
byte[] plainText = cipher.doFinal(byteArray);
return plainText;
} catch(Exception e) {
throw new RuntimeException(e);
}
}
}
3、登陆前要从后台获取公钥
/**
* 登录前生成公钥,用于加密
* @return
* @throws Exception
*/
@PostMapping("/getPublicKey")
public ResResult getPublicKey(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception{
String publicKey = RSAUtils.generateBase64PublicKey();
ResResult res = ResResult.success(publicKey);
return res;
}
4、登录时对加密的数据进行解密,然后登录
/**
* 登录方法
*
* @param loginBody 登录信息
* @return 结果
*/
@ApiOperation(value = "用户登录")
@PostMapping("/userlogin")
public ResResult login(@RequestBody LoginBody loginBody) {
try {
String username = RSAUtils.decryptBase64(loginBody.getUsername()); //对加密的用户名解密
String password = RSAUtils.decryptBase64(loginBody.getPassword());//对加密的密码解密
//开始登录
LoginUser loginUser = loginService.login(username, password,
loginBody.getCode());
String token = tokenService.createToken(loginUser);
} catch (CaptchaExpireException e) {
logger.error(e.getMessage(),e);
return ResResult.error("验证码失效");
} catch (CaptchaException e) {
logger.error(e.getMessage(),e);
return ResResult.error("验证码错误");
}
}
前端代码
1、下载jsencrypt.min.js文件到项目中
2、引入本地 sencrypt.min.js文件
import JSEncrypt from 'static/lib/utils/jsencrypt.min.js'
3、登录前获取公钥
init(){
getPublicKey().then(res => {
this.publicKey = res.msg //公钥信息
Cookies.set(this.publicKeyCookieKey, res.msg, { "expires": 30 })
});
}
4、对用户名和密码进行加密,加密后的数据提价表单
var encrypt = new JSEncrypt();
encrypt.setPublicKey(this.publicKey);
var username = encrypt.encrypt(this.loginForm.username) //开始加密
var password = encrypt.encrypt(this.loginForm.password) //开始加密
let loginData = {
username: username,
password: password,
code: this.loginForm.code
}
//登录
login(loginData).then(res => {
this.goLogin(res)
}).catch(error => {
this.loading = false
})