参考资料:https://astaxie.gitbooks.io/build-web-application-with-golang/content/zh/09.5.html
本文采用方案1进行明文密码的加密操作,Bcrypt是单向Hash加密算法,此算法对于同一个明文密码,每次生成的hash不一样,每次加密,都会采用不同的盐值来进行加密,最后返回的 hash 值包含盐值等信息的密文。
其中:$是分割符,无意义;2a是bcrypt加密版本号;10是cost的值;而后的前22位是salt值;再然后的字符串就是密码的密文了。
go get -u golang.org/x/crypto/bcrypt
bcrypt.GenerateFromPassword([]byte(password), 10)
bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
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.io/zh_CN/docs/hooks.html
使用钩子来实现密码加密后存库,我们之前使用的方式 data.Password = BcryptPW(data.Password)
,替换成钩子后,框架会在写入库前,自动调用钩子函数,来将密码进行加密处理:
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
}
//......
下一节,JWT 的使用,敬请期待...