gin博客项目复盘--04用户密码加密

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 本文采用方案1进行明文密码的加密操作,Bcrypt是单向Hash加密算法,此算法对于同一个明文密码,每次生成的hash不一样,每次加密,都会采用不同的盐值来进行加密,最后返回的 hash 值包含盐值等信息的密文。

参考资料:https://astaxie.gitbooks.io/build-web-application-with-golang/content/zh/09.5.html

  • 方案1:bcrypt
  • 方案2:scrypt(参考资料中的专家方案)

本文采用方案1进行明文密码的加密操作,Bcrypt是单向Hash加密算法,此算法对于同一个明文密码,每次生成的hash不一样,每次加密,都会采用不同的盐值来进行加密,最后返回的 hash 值包含盐值等信息的密文。

image.png

其中:$是分割符,无意义;2a是bcrypt加密版本号;10是cost的值;而后的前22位是salt值;再然后的字符串就是密码的密文了。

  • 安装 crypto/bcrypt
  • go get -u golang.org/x/crypto/bcrypt
  1. 生成hash值
bcrypt.GenerateFromPassword([]byte(password), 10)
复制代码
  • 10 为 cost 默认值,加密级别系数,越大越安全但性能开下也随之增大
  1. 密码验证
bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) 
复制代码
  • 参数1 为保存在数据库中的密码hash(之前加密后的密码)
  • 参数2 为前端传过来要验证的密码
  • 返回值 返回true说明密码验证通过
  1. 完整示例
package main
import (
  "fmt"
  "golang.org/x/crypto/bcrypt"
)
func HashPassword(password string) (string, error) {
  bytes, err := bcrypt.GenerateFromPassword([]byte(password), 10)
  return string(bytes), err
}
func CheckPasswordHash(hash, password string) bool {
  err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
  return err == nil
}
func main() {
  password := "123456"
  hash, _ := HashPassword(password)
  fmt.Println("Password:", password)
  fmt.Println("Hash:    ", hash)
  match := CheckPasswordHash(hash, password)
  fmt.Println("Match:   ", match)
}
复制代码

运行结果:

Password: 123456
Hash:     $2a$10$O.do8guW0m5PAphJuuMH7eVSTRuZAtVNsrLLORH6pMzFWdqCmc2Wu
Match:    true
复制代码

gorm 钩子介绍使用

参考资料 gorm.io/zh_CN/docs/hooks.html


image.png

使用钩子来实现密码加密后存库,我们之前使用的方式 data.Password = BcryptPW(data.Password),替换成钩子后,框架会在写入库前,自动调用钩子函数,来将密码进行加密处理:

image.png

加密及钩子在项目中的使用

model/User.go

package model
import (
  "ginVue3blog/utils/errmsg"
  "golang.org/x/crypto/bcrypt"
  "gorm.io/gorm"
  "log"
)
type User struct {
  gorm.Model
  Username string `gorm:"type:varchar(20);not null " json:"username" validate:"required,min=4,max=12" label:"用户名"`
  Password string `gorm:"type:varchar(500);not null" json:"password" validate:"required,min=6,max=120" label:"密码"`
  Role     int    `gorm:"type:int;DEFAULT:2" json:"role" validate:"required,gte=2" label:"角色码"`
}
//......
// CreateUser 新增用户
func CreateUser(data *User) int {
  //data.Password = BcryptPW(data.Password)
  err := db.Create(&data).Error
  if err != nil {
    return errmsg.ERROR //500
  }
  return errmsg.SUCCSE
}
// ChangePassword 修改密码
func ChangePassword(id int, data *User) int {
  //var user User
  //var maps = make(map[string]interface{})
  //maps["password"] = data.Password
  err = db.Select("password").Where("id=?", id).Updates(&data).Error
  if err != nil {
    return errmsg.ERROR
  }
  return errmsg.SUCCSE
}
//使用钩子 BeforeCreate 密码加密&权限控制
func (u *User) BeforeCreate(_ *gorm.DB) (err error) {
  u.Password = BcryptPW(u.Password)
  u.Role = 2
  return nil
}
func (u *User) BeforeUpdate(_ *gorm.DB) (err error) {
  u.Password = BcryptPW(u.Password)
  return nil
}
// BcryptPW 生成密码
func BcryptPW(password string) string {
  const cost = 10 //加密级别系数,越大越安全但性能开下也随之增大
  HashPw, err := bcrypt.GenerateFromPassword([]byte(password), cost)
  if err != nil {
    log.Fatal(err)
  }
  return string(HashPw)
}
// CheckLoginFront 前台登录
func CheckLoginFront(username, password string) (User, int) {
  var user User
  var PasswordErr error
  db.Where("username=?", username).First(&user)
  PasswordErr = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
  if user.ID == 0 {
    return user, errmsg.ERROR_USER_NOT_EXIST
  }
  if PasswordErr != nil {
    return user, errmsg.ERROR_PASSWORD_WRONG
  }
  return user, errmsg.SUCCSE
}
//......


相关文章
|
3月前
|
存储 NoSQL 数据库
认证服务---整合短信验证码,用户注册和登录 ,密码采用MD5加密存储 【二】
这篇文章讲述了在分布式微服务系统中添加用户注册和登录功能的过程,重点介绍了用户注册时通过远程服务调用第三方服务获取短信验证码、使用Redis进行验证码校验、对密码进行MD5加密后存储到数据库,以及用户登录时的远程服务调用和密码匹配校验的实现细节。
认证服务---整合短信验证码,用户注册和登录 ,密码采用MD5加密存储 【二】
|
1月前
|
存储 Java 数据库
密码专辑:对密码加盐加密,对密码进行md5加密,封装成密码工具类
这篇文章介绍了如何在Java中通过加盐和加密算法(如MD5和SHA)安全地存储密码,并提供了一个密码工具类PasswordUtils和密码编码类PasswordEncoder的实现示例。
30 10
密码专辑:对密码加盐加密,对密码进行md5加密,封装成密码工具类
|
5月前
|
Go 数据安全/隐私保护
go 基于gin编写encode、decode、base64加密接口
go 基于gin编写encode、decode、base64加密接口
48 2
|
1月前
|
NoSQL Java Redis
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
这篇文章介绍了如何使用Spring Boot整合Apache Shiro框架进行后端开发,包括认证和授权流程,并使用Redis存储Token以及MD5加密用户密码。
30 0
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
|
1月前
|
安全 算法 Java
数据库信息/密码加盐加密 —— Java代码手写+集成两种方式,手把手教学!保证能用!
本文提供了在数据库中对密码等敏感信息进行加盐加密的详细教程,包括手写MD5加密算法和使用Spring Security的BCryptPasswordEncoder进行加密,并强调了使用BCryptPasswordEncoder时需要注意的Spring Security配置问题。
128 0
数据库信息/密码加盐加密 —— Java代码手写+集成两种方式,手把手教学!保证能用!
|
6月前
|
算法 数据库 数据安全/隐私保护
rsa加密解密,使用rsa对密码加密
rsa加密解密,使用rsa对密码加密
|
2月前
|
存储 安全 算法
RSA在手,安全我有!Python加密解密技术,让你的数据密码坚不可摧
【9月更文挑战第11天】在数字化时代,信息安全至关重要。传统的加密方法已难以应对日益复杂的网络攻击。RSA加密算法凭借其强大的安全性和广泛的应用场景,成为保护敏感数据的首选。本文介绍RSA的基本原理及在Python中的实现方法,并探讨其优势与挑战。通过使用PyCryptodome库,我们展示了RSA加密解密的完整流程,帮助读者理解如何利用RSA为数据提供安全保障。
123 5
|
2月前
|
安全 数据安全/隐私保护 Python
情书也能加密?Python AES&RSA,让每一份数据都充满爱的密码
【9月更文挑战第8天】在这个数字化时代,情书不再局限于纸笔,也可能以电子形式在网络中传递。为了确保其安全,Python提供了AES和RSA等加密工具,为情书编织爱的密码。首先,通过安装pycryptodome库,我们可以利用AES对称加密算法高效保护数据;接着,使用RSA非对称加密算法加密AES密钥和IV,进一步增强安全性。即使情书被截获,没有正确密钥也无法解读内容。让我们用Python为爱情编织一张安全的网,守护每份珍贵情感。
48 2
|
3月前
|
安全 数据安全/隐私保护 Python