从零开始的IM聊天系统(六)——Md5和密码加密

608 阅读2分钟

无论是什么样的系统,只要有用户,那么用户安全就是不可避免的问题,这节我们会讲解一下Md5和密码加密的方式。

Md5序列化方法

在utils文件夹中新增md5.go文件,用来存放md5相关配置, 添加以下文件:

package utils

import (
   "crypto/md5"
   "encoding/hex"
   "strings"
)

// Md5Encode 小写
func Md5Encode(data string) string {
   h := md5.New()
   h.Write([]byte(data))
   tempStr := h.Sum(nil)
   return hex.EncodeToString(tempStr)
}

// MD5Encode 大写
func MD5Encode(data string) string {
   return strings.ToUpper(Md5Encode(data))
}

密码加密与解密

密码学是一种很复杂的学科,细致起来非常的讲究,所以这里用最简单的方法加密:通过md5序列化和添加随机数。

添加加密解密方法

// MakePassword 加密
func MakePassword(plainpwd, salt string) string {
   return Md5Encode(plainpwd + salt)
}

// ValidPassword 解密
func ValidPassword(plainpwd, salt string, password string) bool {
   return Md5Encode(plainpwd+salt) == password
}

为user结构体中新增随机数字段:Salt

type UserBasic struct {
   gorm.Model
   Name          string `gorm:"column:name" json:"name"`
   Password      string `gorm:"column:password" json:"password"`
   Phone         string `valid:"matches(^1[3-9]{1}\d{9}$)" gorm:"column:phone" json:"phone"`
   Email         string `valid:"email" gorm:"column:email" json:"email"`
   Identity      string `gorm:"column:identity" json:"identity"`
   ClientIp      string `gorm:"column:client_ip" json:"client_ip"`
   ClientPort    string `gorm:"column:client_port" json:"client_port"`
   Salt          string `gorm:"column:salt" json:"salt"`
   LoginTime     uint64 `gorm:"column:login_time" json:"login_time"`
   HeartbeatTime uint64 `gorm:"column:heartbeat_time" json:"heartbeat_time"`
   LoginOutTime  uint64 `gorm:"column:login_out_time" json:"login_out_time"`
   IsLogout      bool   `gorm:"column:is_logout" json:"is_logout"`
   DeviceInfo    string `gorm:"column:device_info" json:"device_info"`
}

将加密方法应用到service中的CreateUser方法中

  1. 生成随机数并将随机数保存到结构体中
  2. 将随机数拼上密码保存起来
// CreateUser
// @Summary 新增用户
// @Tags 用户模块
// @param name query string false "用户名"
// @param password query string false "密码"
// @param rePassword query string false "确认密码"
// @Success 200 {string} json{"code", "message"}
// @Router /user/createUser [get]
func CreateUser(c *gin.Context) {
   user := models.UserBasic{}
   user.Name = c.Query("name")
   password := c.Query("password")
   rePassword := c.Query("rePassword")

   salt := fmt.Sprintf("%06d", rand.Int31())
   user.Salt = salt

   data := models.FindUserByName(user.Name)
   if data.Name != "" {
      c.JSON(-1, gin.H{
         "message": "用户名已经注册",
      })
      return
   }

   if password != rePassword {
      c.JSON(-1, gin.H{
         "message": "两次密码不一致",
      })
      return
   }

   user.Password = utils.MakePassword(password, salt)

   models.CreateUser(&user)

   c.JSON(200, gin.H{
      "message": "新增用户成功",
   })
}

生成新的表单

由于我们为结构体添加了新的字段,所以我们需要重新生成表,运行之前生成表的test方法:

package main

import (
   "ginchat/models"
   "gorm.io/driver/mysql"
   "gorm.io/gorm"
)

func main() {
   db, err := gorm.Open(mysql.Open("用户名:密码@数据库地址/ginchat?charset=utf8mb4&parseTime=True&loc=Local"), &gorm.Config{})
   if err != nil {
      panic("failed to connect database")
   }

   // 迁移 schema
   db.AutoMigrate(&models.UserBasic{})
}

运行main.go文件,新增一个用户:如果出现以下表单,代表已经成功:

image.png