前(Vue)后(Gin)端Rsa加密

说明

本篇相当于是一个hello world,是一个系列的开篇,本系列后面将会包含但不限于

  1. web端rsa加密登录,js混淆
  2. 后端包含支持https,rsa解密
  3. Android端将会包含apk混淆,加固,证书校验(只信任自己的证书)
  4. openssl证书生成等

前端代码

前端是Vue,采用jsencrypt进行加密,请求的时候会有跨域问题

<template>
  <div class="center">
    <el-row>
      <el-col :span="24">
        <el-input prefix-icon="el-icon-user" placeholder="请输入用户名" v-model="username" clearable></el-input>
      </el-col>
    </el-row>
    <el-row>
      <el-col :span="24">
        <el-input prefix-icon="el-icon-lock" placeholder="请输入密码" v-model="password" show-password></el-input>
      </el-col>
    </el-row>
    <el-row>
      <el-col :span="8">
        <el-checkbox v-model="remember_me">记住登录</el-checkbox>
      </el-col>
    </el-row>
    <el-row>
      <el-col :span="24">
        <el-button class="custom-btn" type="primary" plain @click="login()">登录</el-button>
      </el-col>
    </el-row>
    <el-row>
      <el-col :span="24" />
      <el-input type="textarea" :rows="2" placeholder="请输入内容" v-model="textarea"></el-input>
    </el-row>
  </div>
</template>


<script>
import axios from "axios";
import JSEncrypt from "jsencrypt";

export default {
  name: "Login",
  data() {
    return {
      username: "",
      password: "",
      remember_me: false,
      textarea: "",
      publicKey: "",
    };
  },
  created() {
    this.getPubKey();
  },
  methods: {
    getPubKey() {
      const url = "http://127.0.0.1:8081/getPubKey";
      axios
        .get(url)
        .then((response) => {
          console.log("response data is:" + response.data.message);
          this.publicKey = response.data.message;
          //this.textarea = this.publicKey;
        })
        .catch((response) => {
          console.log("请求失败..." + response);
        });
    },

    login() {
      let encryptPd = this.ras_encrypt();
      console.log("password after encrypt is:" + encryptPd);
      const url = "http://127.0.0.1:8081/login";
      let data = {
          "encryptPwd":encryptPd
      }
      axios.post(url, data).then((res) => {
        console.log("res=>", res);
      });
    },

    ras_encrypt() {
      let encryptStr = new JSEncrypt();
      encryptStr.setPublicKey(this.publicKey); // 设置 加密公钥
      let data = encryptStr.encrypt(this.password); // 进行加密
      return data;
    },
  },
};
</script>


<style>
.center {
  margin-left: 100px;
  margin-top: 50px;
  height: 200px;
  width: 300px;
}

.el-row {
  margin-bottom: 10px;
}
.el-col {
  border-radius: 4px;
}

.custom-btn {
  width: 100%;
}
</style>

后端代码

后端采用Golang的Gin并允许跨域

package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"strings"
)


var (
	privateKeyStr string
	publicKeyStr string
)


func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method :=c.Request.Method
		origin := c.Request.Header.Get("Origin")        //请求头部
		var headerKeys []string                             // 声明请求头keys
		for k, _ := range c.Request.Header {
			headerKeys = append(headerKeys, k)
		}
		headerStr := strings.Join(headerKeys, ", ")
		if headerStr != "" {
			headerStr = fmt.Sprintf("access-control-allow-origin, access-control-allow-headers, %s", headerStr)
		} else {
			headerStr = "access-control-allow-origin, access-control-allow-headers"
		}
		if origin != "" {
			c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
			c.Header("Access-Control-Allow-Origin", "*")        // 这是允许访问所有域
			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")      //服务器支持的所有跨域请求的方法,为了避免浏览次请求的多次'预检'请求
			// header的类型
			c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma")
			// 允许跨域设置                                                                                                      可以返回其他子段
			c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar")      // 跨域关键设置 让浏览器可以解析
			c.Header("Access-Control-Max-Age", "172800")        // 缓存请求信息 单位为秒
			c.Header("Access-Control-Allow-Credentials", "false")       //  跨域请求是否需要带cookie信息 默认设置为true
			c.Set("content-type", "application/json")       // 设置返回格式是json
		}
		if method == "OPTIONS" {
			c.JSON(http.StatusOK, "Options Request!")
		}
		c.Next()// 处理请求
	}
}

func StartServer(){

	r := gin.Default()
	r.Use(Cors())
	r.GET("/getPubKey", func(c *gin.Context) {
		if err := GenRsaKey(1024); err != nil {
			fmt.Println("密钥文件生成失败!")
			c.JSON(500,gin.H{
				"message": "server error",
			})
			return
		}
		c.JSON(200, gin.H{
			"message": publicKeyStr,
		})
	})
	r.POST("/login", func(context *gin.Context) {
		type Param struct {
			EncryptPwd string `json:"encryptPwd"`
		}
		var par Param
		err:=context.BindJSON(&par)
		if err!=nil{
			fmt.Println(err.Error())
			context.JSON(200,gin.H{
				"message":"password error",
			})
		}

		fmt.Println("par.EncryptPwd is",par.EncryptPwd)
		data, err := base64.StdEncoding.DecodeString(par.EncryptPwd)
		if err != nil {
			fmt.Println(err.Error())
			return
		}

		passWord,err:=RsaDecrypt(data)
		if err!=nil{
			fmt.Println(err.Error())
			return
		}

		fmt.Println("password is",string(passWord))
		context.JSON(200,gin.H{
			"message":string(passWord),
		})

	})
	r.Run(":8081") // listen and serve on 0.0.0.0:8081

}

func main() {

	StartServer()
}

func RsaEncrypt(origData []byte) ([]byte, error) {
	//解密pem格式的公钥
	block, _ := pem.Decode([]byte(publicKeyStr))
	if block == nil {
		return nil, errors.New("public key error")
	}
	// 解析公钥
	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil, err
	}
	// 类型断言
	pub := pubInterface.(*rsa.PublicKey)
	//加密
	return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)
}

func RsaDecrypt(ciphertext []byte) ([]byte, error) {
	//解密
	block, _ := pem.Decode([]byte(privateKeyStr))
	if block == nil {
		return nil, errors.New("private key error!")
	}
	//解析PKCS1格式的私钥
	priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}
	// 解密
	data,err := rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)
	if err!=nil{
		fmt.Println(err.Error())
		return nil,err
	}
	return data,nil
}



func GenRsaKey(bits int) error {

	// 生成私钥文件
	privateKey, err := rsa.GenerateKey(rand.Reader, bits)

	if err != nil {
		return err
	}
	derStream := x509.MarshalPKCS1PrivateKey(privateKey)
	priBlock := &pem.Block{
		Type:  "RSA PRIVATE KEY",
		Bytes: derStream,
	}

	privateKeyStr = string(pem.EncodeToMemory(priBlock))
	fmt.Printf("=======私钥文件内容=========%v\n", privateKeyStr)
	// 生成公钥文件
	publicKey := &privateKey.PublicKey
	derPkix, err := x509.MarshalPKIXPublicKey(publicKey)
	if err != nil {
		return err
	}
	publicBlock := &pem.Block{
		Type:  "PUBLIC KEY",
		Bytes: derPkix,
	}

	publicKeyStr = string(pem.EncodeToMemory(publicBlock))
	fmt.Printf("=======公钥文件内容=========%v\n", publicKeyStr)

	if err != nil {
		return err
	}
	return nil
}

结果

在这里插入图片描述
后端将解析出来的结果返回到了前端(其实没有必要)

后端结果如下:
在这里插入图片描述
可以看到能正常解密

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值