From dce7e8cb9f8de59e103bf7ca8364d53038a8d912 Mon Sep 17 00:00:00 2001 From: charlie <3140647@qq.com> Date: Wed, 22 Jun 2022 11:23:47 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=86=E7=A0=81=E8=AF=84=E4=BC=B0=EF=BC=8C?= =?UTF-8?q?=E5=AF=86=E7=A0=81=E5=8A=A0=E5=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- password/password_evaluate.go | 44 ++++++++++++++++++++++++++++++++++ password/salt_password.go | 22 +++++++++++++++++ password/salt_password_test.go | 23 ++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 password/password_evaluate.go create mode 100644 password/salt_password.go create mode 100644 password/salt_password_test.go diff --git a/password/password_evaluate.go b/password/password_evaluate.go new file mode 100644 index 0000000..1a34a55 --- /dev/null +++ b/password/password_evaluate.go @@ -0,0 +1,44 @@ +package password + +import ( + "fmt" + "regexp" +) + +const ( + LevelD = iota + LevelC + LevelB + LevelA + LevelS +) + +var patterns = []*regexp.Regexp{ + regexp.MustCompile(`[0-9]+`), // 数字 + regexp.MustCompile(`[a-z]+`), // 小字字母 + regexp.MustCompile(`[A-Z]+`), // 大写字母 + regexp.MustCompile(`[~!@#$%^&*?_-]+`), // 特殊符号 +} + +func PasswordEvaluate(minLength, maxLength int, minLevel int, password string) error { + // 首先校验密码长度是否在范围内 + if len(password) < minLength { + return fmt.Errorf("无效密码: 密码长度小于%d个字符", minLength) + } + if len(password) > maxLength { + return fmt.Errorf("无效密码: 密码的长度大于%d个字符", maxLength) + } + + var level int = LevelD + for _, pattern := range patterns { + if pattern.MatchString(password) { + level++ + } + } + + // 如果最终密码强度低于要求的最低强度,返回并报错 + if level < minLevel { + return fmt.Errorf("密码强度不满足当前策略要求。") + } + return nil +} diff --git a/password/salt_password.go b/password/salt_password.go new file mode 100644 index 0000000..d7bc82c --- /dev/null +++ b/password/salt_password.go @@ -0,0 +1,22 @@ +package password + +import ( + "github.com/charlienet/go-mixed/bytesconv" + "golang.org/x/crypto/bcrypt" +) + +func GenerateFromPassword(pwd []byte) (string, error) { + hash, err := bcrypt.GenerateFromPassword(pwd, bcrypt.DefaultCost) + if err != nil { + return "", err + } + + return bytesconv.BytesToString(hash), nil +} + +func ComparePassword(hashed string, plain []byte) bool { + byteHash := bytesconv.StringToBytes(hashed) + err := bcrypt.CompareHashAndPassword(byteHash, plain) + + return err == nil +} diff --git a/password/salt_password_test.go b/password/salt_password_test.go new file mode 100644 index 0000000..6d4f042 --- /dev/null +++ b/password/salt_password_test.go @@ -0,0 +1,23 @@ +package password + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPassword(t *testing.T) { + pwd := "123456" + + h1, _ := GenerateFromPassword([]byte(pwd)) + t.Log(ComparePassword(h1, []byte(pwd))) + + for i := 0; i < 100; i++ { + h, err := GenerateFromPassword([]byte(pwd)) + if err != nil { + t.Fatal(err) + } + + assert.True(t, ComparePassword(h, []byte(pwd))) + } +}