add admin

This commit is contained in:
2026-08-07 15:40:17 +08:00
parent 10424d23d8
commit 56674a850e
28 changed files with 2066 additions and 569 deletions
+10 -5
View File
@@ -25,11 +25,16 @@ var (
currentMd5 string
)
func GetConfig(key string) interface{} { return runViper.Get(key) }
func GetConfigString(key string) string { return runViper.GetString(key) }
func GetConfigInt(key string) int { return runViper.GetInt(key) }
func GetConfigInt64(key string) int64 { return runViper.GetInt64(key) }
func GetConfigBool(key string) bool { return runViper.GetBool(key) }
func GetConfig(key string) interface{} { return runViper.Get(key) }
func GetConfigString(key string) string {
data := make(map[string]string)
data["encrypt.data_key"] = "u2t9T3luZtoRfhBstkFN6TiIMW38BA8a"
data["encrypt_key"] = "M17fcaPeHDr05H17fcaPH1deDH17l3Bd"
return data[key]
}
func GetConfigInt(key string) int { return runViper.GetInt(key) }
func GetConfigInt64(key string) int64 { return runViper.GetInt64(key) }
func GetConfigBool(key string) bool { return runViper.GetBool(key) }
func InitConfig() {
loadOnce.Do(func() {
+103
View File
@@ -75,3 +75,106 @@ func HmacSha256ToHex(key string, data string) string {
func HmacSha256ToBase64(key string, data string) string {
return base64.URLEncoding.EncodeToString(HmacSha256(key, data))
}
func EncryptPhone(phone string) (string, Error) {
// 提取各部分
prefix := phone[NumberZero:NumberThree] // 前三位
middle := phone[NumberThree:NumberSeven] // 中四位
suffix := phone[NumberSeven:NumberEleven] // 尾四位
newPhone := StringEmpty
username, cErr := Crypto{}.AESEncryptECB(prefix)
if cErr != nil {
return StringEmpty, cErr
}
newPhone = username
username, cErr = Crypto{}.AESEncryptECB(middle)
if cErr != nil {
return StringEmpty, cErr
}
newPhone += username
username, cErr = Crypto{}.AESEncryptECB(suffix)
if cErr != nil {
return StringEmpty, cErr
}
newPhone += username
return newPhone, nil
}
func DecryptPhone(phone string) (string, Error) {
// 提取各部分
prefix := phone[NumberZero:24] // 前三位
middle := phone[24:48] // 中四位
suffix := phone[48:72] // 尾四位
newPhone := StringEmpty
username, cErr := Crypto{}.AESDecryptECB(prefix)
if cErr != nil {
return StringEmpty, cErr
}
newPhone = username
username, cErr = Crypto{}.AESDecryptECB(middle)
if cErr != nil {
return StringEmpty, cErr
}
newPhone += username
username, cErr = Crypto{}.AESDecryptECB(suffix)
if cErr != nil {
return StringEmpty, cErr
}
newPhone += username
return newPhone, nil
}
func getSearchPhone(mobile string) string {
phone := StringEmpty
if len(mobile) == 11 {
prefix := mobile[NumberZero:3] // 前三位
username, cErr := Crypto{}.AESEncryptECB(prefix)
if cErr == nil {
phone = username
}
prefix = mobile[NumberThree:NumberSeven] // 中四位
username, cErr = Crypto{}.AESEncryptECB(prefix)
if cErr == nil {
phone += username
}
prefix = mobile[NumberSeven:NumberEleven] // 尾四位
username, cErr = Crypto{}.AESEncryptECB(prefix)
if cErr == nil {
phone += username
}
} else if len(mobile) > NumberTwo {
prefix := mobile[NumberZero:NumberThree] //前三位
if len(mobile) == NumberFour {
prefix = mobile[NumberZero:NumberFour] // 前四位
}
username, cErr := Crypto{}.AESEncryptECB(prefix)
if cErr == nil {
phone = username
}
if len(mobile) > NumberFour {
prefix = mobile[NumberThree:] // 中四位
username, cErr = Crypto{}.AESEncryptECB(prefix)
if cErr == nil {
phone += username
}
}
}
return phone
}
// GetRandstring 取得随机字符串:使用字符串拼接
func GetRandstring(length int) string {
if length < 1 {
return StringEmpty
}
char := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
charArr := strings.Split(char, StringEmpty)
charlen := len(charArr)
ran := rand.New(rand.NewSource(time.Now().Unix()))
var rchar string = StringEmpty
for i := 1; i <= length; i++ {
rchar = rchar + charArr[ran.Intn(charlen)]
}
return rchar
}
-305
View File
@@ -1,305 +0,0 @@
package utils
import (
"crypto/tls"
"encoding/json"
"fmt"
"net/smtp"
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
dysmsapi20170525 "github.com/alibabacloud-go/dysmsapi-20170525/v3/client"
"github.com/alibabacloud-go/tea/tea"
"github.com/joho/godotenv"
)
// 短信签名常量
const (
//SignLone = "爱萝湾"
SignLone = "爱萝湾上海科技有限公司"
)
// 短信模板CODE常量
const (
SmsCode = "SMS_506160477"
SmsPwd = "SMS_506200455"
)
// 状态码常量(模拟PHP中的Code类)
const (
CodeOK = 0 // 成功状态码
CodeError = -1 // 错误状态码
)
// ResponseData 短信发送返回结构体
type ResponseData struct {
Code int `json:"code"`
Msg interface{} `json:"msg"`
}
type EmailMsg struct {
To []string // 收件人
Cc []string // 抄送
Bcc []string // 密送
Subject string // 标题
Body string // 正文,支持html
IsHTML bool // 是否HTML格式
}
// CreateClient 创建阿里云短信客户端
func CreateClient() (*dysmsapi20170525.Client, error) {
// 加载.env文件(如果需要)
_ = godotenv.Load()
key := GetConfigString("sms.sms_ali_api_key")
secret := GetConfigString("sms.sms_ali_api_secret")
// 初始化配置
config := &openapi.Config{
// 从环境变量获取AccessKey ID
AccessKeyId: &key,
// 从环境变量获取AccessKey Secret
AccessKeySecret: &secret,
}
// 设置短信服务接入点
config.Endpoint = tea.String("dysmsapi.aliyuncs.com")
// 创建客户端
client, err := dysmsapi20170525.NewClient(config)
if err != nil {
return nil, err
}
return client, nil
}
// SendSMS 发送短信主方法
// mobile: 手机号
// code: 短信模板CODE
// data: 模板参数(map格式)
// sign: 短信签名(可选,默认使用SignLone)
func SendSMS(mobile, code string, data map[string]interface{}, sign ...string) ResponseData {
test := GetConfigBool("sms.sms_test")
retData := ResponseData{
Code: CodeOK,
Msg: "",
}
if test {
return retData
}
// 设置默认签名
signName := SignLone
name := GetConfigString("sms.sms_sign")
if name != "" {
signName = name
}
if len(sign) > 0 && sign[0] != "" {
signName = sign[0]
}
// 创建客户端
client, err := CreateClient()
if err != nil {
return ResponseData{
Code: CodeError,
Msg: fmt.Sprintf("创建客户端失败: %s", err.Error()),
}
}
// 转换模板参数为JSON字符串
templateParam, err := json.Marshal(data)
if err != nil {
return ResponseData{
Code: CodeError,
Msg: fmt.Sprintf("参数JSON编码失败: %s", err.Error()),
}
}
// 构建发送短信请求
sendSmsRequest := &dysmsapi20170525.SendSmsRequest{
PhoneNumbers: tea.String(mobile),
SignName: tea.String(signName),
TemplateCode: tea.String(code),
TemplateParam: tea.String(string(templateParam)),
}
Logger.Error(signName, "m=", mobile, "<UNK>:", sendSmsRequest, "2=", code, "tmpo:", string(templateParam))
// 发送短信
response, err := client.SendSms(sendSmsRequest)
if err != nil {
// 处理错误
retData.Code = CodeError
retData.Msg = fmt.Sprintf("发送短信失败: %s", err.Error())
return retData
}
statusCode := *response.StatusCode
// 检查响应状态
if statusCode != 200 {
retData.Code = CodeError
}
// 将响应转换为map返回
retData.Msg = map[string]interface{}{
"StatusCode": response.StatusCode,
"Body": response.Body,
}
return retData
}
// 简化调用示例(可选)
// SendCodeSMS 发送验证码短信
func SendCodeSMS(mobile string, code string) ResponseData {
data := map[string]interface{}{
"code": code,
}
code = getConfig("sms.sms_code_sign")
if code == "" {
code = SmsCode
}
return SendSMS(mobile, code, data)
}
func SendCodeMail(msg EmailMsg) ResponseData {
user := GetConfigString("sms.sms_mail_user")
pwd := GetConfigString("sms.sms_mail_pwd")
host := GetConfigString("sms.sms_mail_host")
port := GetConfigInt("sms.sms_mail_port")
name := GetConfigString("sms.sms_mail_show_name")
auth := smtp.PlainAuth("", user, pwd, host)
from := fmt.Sprintf("%s <%s>", name, user)
// 构建邮件头部
var header string
header += fmt.Sprintf("From: %s\r\n", from)
header += fmt.Sprintf("To: %s\r\n", joinStrings(msg.To, ","))
if len(msg.Cc) > 0 {
header += fmt.Sprintf("Cc: %s\r\n", joinStrings(msg.Cc, ","))
}
if len(msg.Bcc) > 0 {
header += fmt.Sprintf("Bcc: %s\r\n", joinStrings(msg.Bcc, ","))
}
header += fmt.Sprintf("Subject: %s\r\n", msg.Subject)
contentType := "text/plain; charset=utf-8"
if msg.IsHTML {
contentType = "text/html; charset=utf-8"
}
header += fmt.Sprintf("Content-Type: %s\r\n\r\n", contentType)
fullMsg := []byte(header + msg.Body)
tlsConfig := &tls.Config{
ServerName: host,
}
addr := fmt.Sprintf("%s:%d", host, port)
// 1. 先建立SSL连接(465端口)
conn, err := tls.Dial("tcp", addr, tlsConfig)
if err != nil {
Logger.Error("tls dial err:", err)
return ResponseData{
Code: CodeError,
Msg: err.Error(),
}
}
// 2. 关键:用加密连接创建smtp client
client, err := smtp.NewClient(conn, host)
if err != nil {
_ = conn.Close()
Logger.Error("smtp.NewClient err:", err)
return ResponseData{
Code: CodeError,
Msg: err.Error(),
}
}
// 由client统一管理连接关闭
defer client.Close()
if err = client.Auth(auth); err != nil {
Logger.Error("client.Auth err:", err)
return ResponseData{
Code: CodeError,
Msg: err.Error(),
}
}
if err = client.Mail(user); err != nil {
Logger.Error("client.Mail err:", err)
return ResponseData{
Code: CodeError,
Msg: err.Error(),
}
}
receivers := append(append(msg.To, msg.Cc...), msg.Bcc...)
for _, r := range receivers {
if err = client.Rcpt(r); err != nil {
Logger.Error("client.Rcpt err:", err, "rcpt:", r)
return ResponseData{
Code: CodeError,
Msg: err.Error(),
}
}
}
w, err := client.Data()
if err != nil {
Logger.Error("client.Data err:", err)
return ResponseData{
Code: CodeError,
Msg: err.Error(),
}
}
_, err = w.Write(fullMsg)
if err != nil {
Logger.Error("write mail body err:", err)
return ResponseData{
Code: CodeError,
Msg: err.Error(),
}
}
err = w.Close()
if err != nil {
Logger.Error("w.Close err:", err)
return ResponseData{
Code: CodeError,
Msg: err.Error(),
}
}
err = client.Quit()
if err != nil {
Logger.Error("client.Quit err:", err)
return ResponseData{
Code: CodeError,
Msg: "smtp quit failed: " + err.Error(),
}
}
return ResponseData{
Code: CodeOK,
Msg: "",
}
}
func joinStrings(arr []string, sep string) string {
if len(arr) == 0 {
return ""
}
res := arr[0]
for i := 1; i < len(arr); i++ {
res += sep + arr[i]
}
return res
}
// SendPwdSMS 发送密码相关短信
func SendPwdSMS(mobile string, pwd string) ResponseData {
data := map[string]interface{}{
"code": pwd,
}
code := getConfig("sms.sms_pwd_sign")
if code == "" {
code = SmsPwd
}
return SendSMS(mobile, code, data)
}
+12 -5
View File
@@ -17,6 +17,9 @@ const (
NumberSeven = 7
NumberEight = 8
NumberNine = 9
NumberTen = 10
NumberEleven = 11
NumberTwelve = 12
NumberSixteen = 16
NumberThirtyTwo = 32
@@ -31,6 +34,9 @@ const (
CentralHorizontalLine = " - "
DecollatorEqual = "="
StringEmpty = ""
StringDot = "."
StringStatusOk = "1"
StringStatusNo = "2"
)
const (
@@ -52,10 +58,14 @@ const (
var (
//新使用方法
Ok = Status{Code: 10000, Msg: "OK"}
Ok = Status{Code: 10000, Msg: "OK"}
Fail = Status{Code: 999, Msg: "fail"}
ErrorParams = Status{Code: 10001, Msg: "缺少参数或传值不对"}
ErrorEncryptAesError = Status{Code: 10001, Msg: "加密失败"}
ErrorNotFund = Status{Code: 11001, Msg: "not fund"}
ErrorExistUser = Status{Code: 10009, Msg: "账号或手机号已存在"}
// 基础类
Fail = NewError(999, "fail")
ErrorExist = NewError(998, "已存在")
ErrorOvertime = NewError(997, "请求已超时")
ErrorDataTransform = NewError(996, "数据转换失败")
@@ -63,7 +73,6 @@ var (
ErrorWecomHttpError = NewError(994, "企业微信请求失败")
// 参数类
ErrorMissingParams = NewError(10001, "缺少参数")
ErrorReasonParams = NewError(10001, "原因不能为空")
ErrorPwdError = NewError(10002, "密码错误")
ErrorNoLogin = NewError(10003, "没有登录")
@@ -74,14 +83,12 @@ var (
ErrorAuthority = NewError(10008, "没有权限")
ErrorMobileError = NewError(10009, "手机号不对")
ErrorEncryptMissingKey = NewError(10010, "加密密钥错误")
ErrorEncryptAesError = NewError(10011, "加密失败")
ErrorDecryptAesError = NewError(10012, "解密失败")
ErrorEncryptAesKeyError = NewError(10013, "AESKey失败")
ErrorEncryptBase64Error = NewError(10014, "解码失败")
ErrorNameInexistence = NewError(10015, "账号不存在")
// ErrorNotFund 数据类
ErrorNotFund = NewError(11001, "not fund")
ErrorNoChange = NewError(11002, "没有改变")
ErrorDataIsExist = NewError(11004, "数据已存在")
ErrorRepeatPayment = NewError(11005, "不能重复支付")