diff --git a/config/conf.go b/config/conf.go index b0772c83ef07a353154e4e08cd925b6b51a38811..99702ba175aa1f84f637de15a62c1ea9961b0696 100644 --- a/config/conf.go +++ b/config/conf.go @@ -15,6 +15,8 @@ package conf import ( "context" "database/sql" + "fmt" + "github.com/bwmarrin/snowflake" "github.com/casbin/casbin/v2" "github.com/casbin/casbin/v2/model" gormadapter "github.com/casbin/gorm-adapter/v3" @@ -147,7 +149,7 @@ func (i Init) Redis() *redis.Client { * @Description: 初始化Casbin * @receiver i */ -func (i Init) Casbin() (Enforcer *casbin.Enforcer) { +func (i Init) Casbin() (Enforcer *casbin.SyncedEnforcer) { // Gorm适配器 adapter, err := gormadapter.NewAdapterByDB(global.DB) if err != nil { @@ -173,7 +175,7 @@ func (i Init) Casbin() (Enforcer *casbin.Enforcer) { `) // 通过ORM新建一个执行者 - Enforcer, err = casbin.NewEnforcer(m, adapter) + Enforcer, err = casbin.NewSyncedEnforcer(m, adapter) if err != nil { panic("新建Casbin执行者异常:" + err.Error()) } @@ -225,3 +227,12 @@ func (i Init) Validate() *validator.Validate { v := validator.New() return v } + +func (i Init) Node() *snowflake.Node { + nodeNum := global.V.GetInt64("Distributed.Node") + node, err := snowflake.NewNode(nodeNum) + if err != nil { + fmt.Println(err) + } + return node +} diff --git a/global/conn.go b/global/conn.go index 7c4cbb02da9e4a7970c70fc75155d4169b56d0fc..bf165619170cdff86847be3b20ee17feab7c3193 100644 --- a/global/conn.go +++ b/global/conn.go @@ -13,6 +13,7 @@ package global import ( + "github.com/bwmarrin/snowflake" "github.com/casbin/casbin/v2" "github.com/go-playground/validator/v10" "github.com/go-redis/redis/v8" @@ -21,10 +22,11 @@ import ( ) var ( - E *Env // 环境类型实例 - V *viper.Viper // Viper实例 - Enforcer *casbin.Enforcer // Casbin执行者 - DB *gorm.DB // 数据库连接池 - RDB *redis.Client // Redis连接池 - Validate *validator.Validate // Validate参数校验器 + E *Env // 环境类型实例 + V *viper.Viper // Viper实例 + Enforcer *casbin.SyncedEnforcer // Casbin执行者 + DB *gorm.DB // 数据库连接池 + RDB *redis.Client // Redis连接池 + Validate *validator.Validate // Validate参数校验器 + Node *snowflake.Node // 雪花ID节点 ) diff --git a/global/constants.go b/global/constants.go index 64fbae6fc6300767fce405e09cc27477dcfb55cf..7ef1030fb64b823b5197e3023a02fe0247c2b13f 100644 --- a/global/constants.go +++ b/global/constants.go @@ -16,9 +16,7 @@ package global type Env = string const ( - ENV_DEV Env = "dev" // 开发环境 - ENV_PRO Env = "pro" // 生产环境 - ENV_TEST Env = "test" // 测试环境 - ENV_RET Env = "ren" // 回归环境 - ENV_FAT Env = "fat" // 预发布环境 + ENV_DEV Env = "dev" // 开发环境 + ENV_PRO Env = "pro" // 生产环境 + ENV_FAT Env = "fat" // 测试环境 ) diff --git a/global/model.go b/global/model.go index b2ac1fd417ae0d6cc691da6f4f9f50295a0494e7..fe4948e301d015bf64e8c275c82814a253b5496c 100644 --- a/global/model.go +++ b/global/model.go @@ -13,19 +13,11 @@ package global import ( - "fmt" - "github.com/bwmarrin/snowflake" - "sync" "time" "github.com/melf-xyzh/gin-start/utils/dtype" ) -var ( - // 定义一个锁 - idLock sync.Mutex -) - type Model struct { ID dtype.DistributedId `json:"id,omitempty" gorm:"column:id;primary_key;"` CreateTime dtype.Time `json:"createTime,omitempty" gorm:"column:create_time;comment:创建时间;"` @@ -38,18 +30,7 @@ type Model struct { * @return DistributedId */ func CreateId() dtype.DistributedId { - idLock.Lock() - defer idLock.Unlock() - - // Create a new Node with a Node number of 1 - // node, err := snowflake.NewNode(nodeNum) - // 为编号为nodeNum的节点生成一个节点 - nodeNum := V.GetInt64("Distributed.Node") - node, err := snowflake.NewNode(nodeNum) - if err != nil { - fmt.Println(err) - } - id := node.Generate() + id := Node.Generate() return dtype.DistributedId(id.Int64()) } diff --git a/menu/model/menu.go b/menu/model/menu.go new file mode 100644 index 0000000000000000000000000000000000000000..dfef26f3ae6415d7b7af2647e259245c18683abe --- /dev/null +++ b/menu/model/menu.go @@ -0,0 +1,24 @@ +/** + * @Time :2022/3/6 18:24 + * @Author :MELF晓宇 + * @Email :xyzh.melf@petalmail.com + * @FileName:menu.go + * @Project :gin-start + * @Blog :https://blog.csdn.net/qq_29537269 + * @Guide :https://guide.melf.space + * @Information: + * + */ + +package model + +import "github.com/melf-xyzh/gin-start/global" + +type Menu struct { + global.Model + MenuName string + Sort uint + Url string + RouterName string + IsShow int +} diff --git a/utils/crypto/aes.go b/utils/crypto/aes.go new file mode 100644 index 0000000000000000000000000000000000000000..582c4d93c255ed22f8f31bcf34943ea6b4ce06cd --- /dev/null +++ b/utils/crypto/aes.go @@ -0,0 +1,160 @@ +/** + * @Time :2022/4/17 16:17 + * @Author :MELF晓宇 + * @Email :xyzh.melf@petalmail.com + * @FileName:aes.go + * @Project :gin-start + * @Blog :https://blog.csdn.net/qq_29537269 + * @Guide :https://guide.melf.space + * @Information: + * + */ + +package crypto + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "encoding/base64" + "errors" + "github.com/melf-xyzh/gin-start/global" +) + +// 高级加密标准(Advanced Encryption Standard,AES) + +type AesCrypto struct{} + +var AES = new(AesCrypto) + +// EnPwdCode +/** + * @Description: 加密base64 + * @param pwd + * @return string + * @return error + */ +func (aesCrypto *AesCrypto) EnPwdCode(pwd []byte) (string, error) { + aesPwd := global.V.GetString("AES.Password") + if aesPwd == "" { + panic("AES.Password未初始化") + } + // pwdKey 加密钥匙,16,24,32位字符串的话,分别对应AES-128,AES-192,AES-256 加密方法 + pwdKey := []byte(aesPwd) + result, err := aesEncrypt(pwd, pwdKey) + if err != nil { + return "", err + } + return base64.StdEncoding.EncodeToString(result), err +} + +// DePwdCode +/** + * @Description: 解密 + * @param pwd + * @return []byte + * @return error + */ +func (aesCrypto *AesCrypto) DePwdCode(pwd string) ([]byte, error) { + aesPwd := global.V.GetString("AES.Password") + if aesPwd == "" { + panic("AES.Password未初始化") + } + // pwdKey 加密钥匙,16,24,32位字符串的话,分别对应AES-128,AES-192,AES-256 加密方法 + pwdKey := []byte(aesPwd) + //解密base64字符串 + pwdByte, err := base64.StdEncoding.DecodeString(pwd) + if err != nil { + return nil, err + } + //执行AES解密 + return aesDecrypt(pwdByte, pwdKey) +} + +// pkcs7Padding +/** + * @Description: PKCS7 填充模式 + * @param ciphertext + * @param blockSize + * @return []byte + */ +func pkcs7Padding(ciphertext []byte, blockSize int) []byte { + padding := blockSize - len(ciphertext)%blockSize + // Repeat()函数的功能是把切片[]byte{byte(padding)}复制padding个,然后合并成新的字节切片返回 + paddingText := bytes.Repeat([]byte{byte(padding)}, padding) + return append(ciphertext, paddingText...) +} + +// PKCS7UnPadding +/** + * @Description:填充的反向操作,删除填充字符串 + * @param origData + * @return []byte + * @return error + */ +func pkcs7UnPadding(origData []byte) ([]byte, error) { + //获取数据长度 + length := len(origData) + if length == 0 { + return nil, errors.New("加密字符串错误!") + } + //获取填充字符串长度 + unPadding := int(origData[length-1]) + //截取切片,删除填充字节,并且返回明文 + return origData[:(length - unPadding)], nil +} + +// aesEncrypt +/** + * @Description: 实现加密 + * @param origData + * @param key + * @return []byte + * @return error + */ +func aesEncrypt(origData []byte, key []byte) ([]byte, error) { + //创建加密算法实例 + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + //获取块的大小 + blockSize := block.BlockSize() + //对数据进行填充,让数据长度满足需求 + origData = pkcs7Padding(origData, blockSize) + //采用AES加密方法中CBC加密模式 + blocMode := cipher.NewCBCEncrypter(block, key[:blockSize]) + crypted := make([]byte, len(origData)) + //执行加密 + blocMode.CryptBlocks(crypted, origData) + return crypted, nil +} + +// aesDecrypt +/** + * @Description: 实现解密 + * @param cypted + * @param key + * @return []byte + * @return error + */ +func aesDecrypt(cypted []byte, key []byte) ([]byte, error) { + //创建加密算法实例 + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + //获取块大小 + blockSize := block.BlockSize() + //创建加密客户端实例 + blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) + origData := make([]byte, len(cypted)) + //这个函数也可以用来解密 + blockMode.CryptBlocks(origData, cypted) + //去除填充字符串 + origData, err = pkcs7UnPadding(origData) + if err != nil { + return nil, err + } + return origData, err +} diff --git a/utils/result/result.go b/utils/result/result.go index 92dbe58235eba8a5c09eaa346462ce131f7bf6c3..ce3fafa1b460eb299f906cc0fd4057eaeb0ac7db 100644 --- a/utils/result/result.go +++ b/utils/result/result.go @@ -102,3 +102,62 @@ func File(c *gin.Context, fileName, filePath string) { c.Header("Content-Type", "application/octet-stream") c.File(filePath) } + +// OkView +/** + * @Description: 返回成功界面 + * @param c + * @param tmplPath tmpl文件路径 + * @param title 网页标题 + * @param msg + */ +func OkView(c *gin.Context, tmplPath, title, msg string) { + c.HTML(http.StatusOK, tmplPath, gin.H{ + "code": CODE_SUCCESS, + "title": title, + "msg": msg, + }) +} + +// FailView +/** + * @Description: 返回失败界面 + * @param c + * @param tmplPath tmpl文件路径 + * @param title 网页标题 + * @param msg + */ +func FailView(c *gin.Context, tmplPath, title, msg string) { + c.HTML(http.StatusOK, tmplPath, gin.H{ + "code": CODE_FAIL, + "title": title, + "msg": msg, + }) +} + +// View +/** + * @Description: 返回界面 + * @param c + * @param tmplPath + * @param title + */ +func View(c *gin.Context, tmplPath, title string) { + c.HTML(http.StatusOK, tmplPath, gin.H{ + "code": CODE_FAIL, + "title": title, + }) +} + +// DataView +/** + * @Description: 返回数据界面 + * @param c + * @param tmplPath + * @param title + * @param data + */ +func DataView(c *gin.Context, tmplPath, title string, data map[string]interface{}) { + data["title"] = title + c.HTML(http.StatusOK, tmplPath, data) +}