添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

通常跟服务器的交互中,为保障数据传输的安全性,避免被人抓包篡改数据,除了 https 的应用,还需要对传输数据进行加解密。

本文介绍一种 RSA 加密 web 前端用户名密码加密传输至后台并解密 的方法。

公共类 RSAUtils

可能需要引入 Jar 包:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.67</version>
</dependency>

编写加解密公共方法类 RSAUtils

import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPublicKey;
public class RSAUtils {
	private static final KeyPair keyPair = initKey();
	private static KeyPair initKey() {
		try {
			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 static String generateBase64PublicKey() {
		PublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
		return new String(Base64.encodeBase64(publicKey.getEncoded()));
	public static String decryptBase64(String string) {
		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 cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider);
			PrivateKey privateKey = keyPair.getPrivate();
			cipher.init(Cipher.DECRYPT_MODE, privateKey);
			byte[] plainText = cipher.doFinal(byteArray);
			return plainText;
		} catch (Exception e) {
			throw new RuntimeException(e);

后台生成公钥方法

@RequestMapping(value = "getPublicKey")
public @ResponseBody String getPublicKey(HttpServletRequest request){
    String publicKey = RSAUtils.generateBase64PublicKey();
    return publicKey;

前端获取公钥

前端在向后台发起登录请求之前,先请求后台获取公钥的方法

var publicKey;
$.ajax({
    url: "getPublicKey",
    type: "get",
    async: false,
    dataType: "text",
    success: function(data) {
        if(data){
            publicKey = data;
});

前端引入加密依赖

前端引入 jsencrypt.min.js 文件:

<script src="/js/jsencrypt.min.js"></script>

npm 引入:

npm i jsencrypt

npm 使用:

import JsEncrypt from 'jsencrypt'
let encrypt = new JsEncrypt();
encrypt.setPublicKey(publicKey);
username = encrypt.encrypt(username.trim());
  • 官网:http://travistidwell.com/jsencrypt/
  • GitHub:https://github.com/travist/jsencrypt
  • npm:https://www.npmjs.com/package/jsencrypt
  • 前端加密

    通过公钥对用户名和密码加密

    var encrypt = new JSEncrypt();
    encrypt.setPublicKey(publicKey);
    var loginaccount = $('#loginaccount').val();
    var loginpassword = $('#loginpassword').val();
    loginaccount = encrypt.encrypt(loginaccount.trim());
    loginpassword = encrypt.encrypt(loginpassword.trim());

    加密请求后台

    方法一:ajax 请求

    通过 ajax 用加密后的用户名密码请求后台

    $.ajax({
    	type: "POST",
    	url: "xxxxxx",
    	data: {
    		"username":username,
    		"password":password,
    	dataType: "json",
    	success: function (result) {
    		if (result.code == 0) {//登录成功
    			parent.location.href = 'index.html';
    		} else {
    			vm.error = true;
    			vm.errorMsg = result.msg;
    			vm.refreshCode();
    });

    方法二:form 表单

    使用 form 表单请求后台

    <form method="post" action="login" id="loginForm" onsubmit="return checkLoginTask()">
    	<input type="hidden" id="account" name="account" />
    	<input type="hidden" id="password" name="password" />
    </form>
    <button onclick="$('#loginForm').submit()">登录</button>

    其中 checkLoginTask 方法如下:

    function checkLoginTask(){
    	var publicKey;
    	$.ajax({
            url: "getPublicKey",
            type: "get",
            async: false,
            dataType: "text",
            success: function(data) {
                if(data){
                    publicKey = data;
        });
        if(publicKey == null){
        	return false;
        var encrypt = new JSEncrypt();
        encrypt.setPublicKey(publicKey);
    	var loginaccount = $('#loginaccount').val();
    	var loginpassword = $('#loginpassword').val();
    	loginaccount = encrypt.encrypt(loginaccount.trim());
    	loginpassword = encrypt.encrypt(loginpassword.trim());
        $('#account').val(loginaccount);
        $('#password').val(loginpassword);
        return true;
    

    方法三:axios 请求

    const { data: publicKey } = await this.$http.get("/user/key");
    var username = this.loginForm.username;
    var password = this.loginForm.password;
    let encrypt = new JsEncrypt();
    encrypt.setPublicKey(publicKey);
    username = encrypt.encrypt(username.trim());
    password = encrypt.encrypt(password.trim());
    console.log(username)
    //发起登入请求
    const { data: res } = await this.$http.post(
        "user/login?username="+encodeURIComponent(username)+"&password="+encodeURIComponent(password)
    

    后端解密

    String account = request.getParameter("account");
    String password = request.getParameter("password");
    if (StringUtils.isNotBlank(account)) {
        account = RSAUtils.decryptBase64(account.trim());
    if (StringUtils.isNotBlank(password)) {
        password = RSAUtils.decryptBase64(password.trim());
    

    从而可以避免出现密码明文传输问题。

    测试代码

    String key = HttpClient4.doGet("http://127.0.0.1:8181/user/key");
    log.info(key);
    Map<String, Object> paramMap = new HashMap<>();
    try{
        paramMap.put("username", RSAUtils.encryptByPublicKey(key,"admin"));
        paramMap.put("password", RSAUtils.encryptByPublicKey(key,"123456"));
        String result = HttpClient4.doPost("http://127.0.0.1:8181/user/login", paramMap);
        log.info(result);
        JsonObject jsonObject = new JsonParser().parse(result).getAsJsonObject();
        if (jsonObject.get("code").getAsInt()==200){
            log.info(jsonObject.get("data").getAsString());
    } catch (Exception e){
        log.error(e.getMessage(),e);
     * 公钥加密
     * @param publicKeyText 公钥
     * @param text 待加密的文本
     * @return /
    public static String encryptByPublicKey(String publicKeyText, String text) throws Exception {
    	X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
    	KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    	PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2);
    	Cipher cipher = Cipher.getInstance("RSA");
    	cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    	byte[] result = cipher.doFinal(text.getBytes());
    	return Base64.encodeBase64String(result);
     * 私钥解密
     * @param privateKeyText
     * @param text
     * @return
     * @throws Exception
    public static String decryptByPrivateKey(String privateKeyText, String text) throws Exception {
    	PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
    	KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    	PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
    	Cipher cipher = Cipher.getInstance("RSA");
    	cipher.init(Cipher.DECRYPT_MODE, privateKey);
    	byte[] result = cipher.doFinal(Base64.decodeBase64(text));
    	return new String(result);