first commit
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
// JWT密钥
|
||||
var jwtSecret = []byte("yunzer_jwt_secret_key") // 在实际应用中应从配置文件读取
|
||||
|
||||
// Claims 定义JWT的claims结构
|
||||
type Claims struct {
|
||||
UserID int `json:"user_id"`
|
||||
Username string `json:"username"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
// GenerateToken 生成JWT token
|
||||
func GenerateToken(userID int, username string) (string, error) {
|
||||
// 设置token过期时间
|
||||
expirationTime := time.Now().Add(24 * time.Hour) // 24小时后过期
|
||||
|
||||
// 创建claims
|
||||
claims := &Claims{
|
||||
UserID: userID,
|
||||
Username: username,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
ExpiresAt: jwt.NewNumericDate(expirationTime),
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
NotBefore: jwt.NewNumericDate(time.Now()),
|
||||
},
|
||||
}
|
||||
|
||||
// 创建token对象,指定签名算法和claims
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
|
||||
// 生成签名并获取完整的编码后的字符串token
|
||||
tokenString, err := token.SignedString(jwtSecret)
|
||||
|
||||
return tokenString, err
|
||||
}
|
||||
|
||||
// ParseToken 解析JWT token
|
||||
func ParseToken(tokenString string) (*Claims, error) {
|
||||
// 解析token
|
||||
claims := &Claims{}
|
||||
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
|
||||
// 验证签名算法
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, errors.New("unexpected signing method")
|
||||
}
|
||||
return jwtSecret, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !token.Valid {
|
||||
return nil, errors.New("invalid token")
|
||||
}
|
||||
|
||||
return claims, nil
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
"github.com/beego/beego/v2/client/orm"
|
||||
)
|
||||
|
||||
// FileInfo 文件信息模型
|
||||
// 对应 yz_files 表结构
|
||||
type FileInfo struct {
|
||||
ID int64 `orm:"column(id);auto" json:"id"`
|
||||
TenantID string `orm:"column(tenant_id);size(64)" json:"tenant_id"`
|
||||
|
||||
// 用户关联信息(通过JWT认证获取)
|
||||
UserID int `orm:"column(user_id);default(0)" json:"user_id"`
|
||||
|
||||
// 文件基础信息
|
||||
FileName string `orm:"column(file_name);size(255)" json:"file_name"`
|
||||
OriginalName string `orm:"column(original_name);size(255)" json:"original_name"`
|
||||
FilePath string `orm:"column(file_path);size(500)" json:"file_path"`
|
||||
FileURL string `orm:"column(file_url);size(500);null" json:"file_url"`
|
||||
FileSize int64 `orm:"column(file_size);default(0)" json:"file_size"`
|
||||
FileType string `orm:"column(file_type);size(50)" json:"file_type"`
|
||||
FileExt string `orm:"column(file_ext);size(20)" json:"file_ext"`
|
||||
|
||||
// 分类信息
|
||||
Category string `orm:"column(category);size(100)" json:"category"`
|
||||
SubCategory string `orm:"column(sub_category);size(100);null" json:"sub_category"`
|
||||
|
||||
// 状态信息
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"`
|
||||
IsPublic int8 `orm:"column(is_public);default(0)" json:"is_public"`
|
||||
|
||||
// 上传信息
|
||||
UploadBy string `orm:"column(upload_by);size(100)" json:"upload_by"`
|
||||
UploadTime time.Time `orm:"column(upload_time);type(datetime);auto_now_add" json:"upload_time"`
|
||||
|
||||
// 关联的用户信息(非数据库字段)
|
||||
User *User `orm:"-" json:"user,omitempty"`
|
||||
}
|
||||
|
||||
// TableName 设置表名
|
||||
func (f *FileInfo) TableName() string {
|
||||
return "yz_files"
|
||||
}
|
||||
|
||||
// GetAllFiles 获取所有文件信息
|
||||
func GetAllFiles() ([]*FileInfo, error) {
|
||||
o := orm.NewOrm()
|
||||
var files []*FileInfo
|
||||
_, err := o.QueryTable("yz_files").Filter("status", 1).OrderBy("-upload_time").All(&files)
|
||||
return files, err
|
||||
}
|
||||
|
||||
// GetFilesByUserID 根据用户ID获取文件列表
|
||||
func GetFilesByUserID(userID int) ([]*FileInfo, error) {
|
||||
o := orm.NewOrm()
|
||||
var files []*FileInfo
|
||||
_, err := o.QueryTable("yz_files").Filter("user_id", userID).Filter("status", 1).OrderBy("-upload_time").All(&files)
|
||||
return files, err
|
||||
}
|
||||
|
||||
// GetFileById 根据ID获取文件信息
|
||||
func GetFileById(id int64) (*FileInfo, error) {
|
||||
o := orm.NewOrm()
|
||||
file := &FileInfo{ID: id}
|
||||
err := o.Read(file, "ID")
|
||||
if err == orm.ErrNoRows {
|
||||
return nil, err
|
||||
}
|
||||
return file, nil
|
||||
}
|
||||
|
||||
// GetFilesByTenant 根据租户ID获取文件信息
|
||||
func GetFilesByTenant(tenantID string) ([]*FileInfo, error) {
|
||||
o := orm.NewOrm()
|
||||
var files []*FileInfo
|
||||
_, err := o.QueryTable("yz_files").Filter("tenant_id", tenantID).OrderBy("-upload_time").All(&files)
|
||||
return files, err
|
||||
}
|
||||
|
||||
// GetFilesByCategory 根据分类获取文件信息
|
||||
func GetFilesByCategory(category string) ([]*FileInfo, error) {
|
||||
o := orm.NewOrm()
|
||||
var files []*FileInfo
|
||||
_, err := o.QueryTable("yz_files").Filter("category", category).OrderBy("-upload_time").All(&files)
|
||||
return files, err
|
||||
}
|
||||
|
||||
// GetFilesByStatus 根据状态获取文件信息
|
||||
func GetFilesByStatus(status int8) ([]*FileInfo, error) {
|
||||
o := orm.NewOrm()
|
||||
var files []*FileInfo
|
||||
_, err := o.QueryTable("yz_files").Filter("status", status).OrderBy("-upload_time").All(&files)
|
||||
return files, err
|
||||
}
|
||||
|
||||
// AddFile 添加新文件信息
|
||||
func AddFile(file *FileInfo) (int64, error) {
|
||||
o := orm.NewOrm()
|
||||
id, err := o.Insert(file)
|
||||
return id, err
|
||||
}
|
||||
|
||||
// UpdateFile 更新文件信息
|
||||
func UpdateFile(file *FileInfo) error {
|
||||
o := orm.NewOrm()
|
||||
_, err := o.Update(file)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteFile 删除文件信息(软删除,设置状态为0)
|
||||
func DeleteFile(id int64) error {
|
||||
o := orm.NewOrm()
|
||||
file := &FileInfo{ID: id}
|
||||
if err := o.Read(file, "ID"); err != nil {
|
||||
return err
|
||||
}
|
||||
file.Status = 0
|
||||
_, err := o.Update(file, "Status")
|
||||
return err
|
||||
}
|
||||
|
||||
// HardDeleteFile 硬删除文件信息
|
||||
func HardDeleteFile(id int64) error {
|
||||
o := orm.NewOrm()
|
||||
_, err := o.Delete(&FileInfo{ID: id})
|
||||
return err
|
||||
}
|
||||
|
||||
// GetFileStatistics 获取文件统计信息
|
||||
func GetFileStatistics(tenantID string) (map[string]interface{}, error) {
|
||||
o := orm.NewOrm()
|
||||
|
||||
// 总文件数
|
||||
totalCount, err := o.QueryTable("yz_files").Filter("tenant_id", tenantID).Filter("status", 1).Count()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 总文件大小
|
||||
var totalSize int64
|
||||
err = o.Raw("SELECT COALESCE(SUM(file_size), 0) FROM yz_files WHERE tenant_id = ? AND status = 1", tenantID).QueryRow(&totalSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 按分类统计
|
||||
var categoryStats []orm.Params
|
||||
_, err = o.Raw("SELECT category, COUNT(*) as count, COALESCE(SUM(file_size), 0) as size FROM yz_files WHERE tenant_id = ? AND status = 1 GROUP BY category", tenantID).Values(&categoryStats)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"total_count": totalCount,
|
||||
"total_size": totalSize,
|
||||
"category_stats": categoryStats,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SearchFiles 搜索文件
|
||||
func SearchFiles(keyword string, tenantID string) ([]*FileInfo, error) {
|
||||
o := orm.NewOrm()
|
||||
var files []*FileInfo
|
||||
|
||||
// 构建查询条件
|
||||
qs := o.QueryTable("yz_files").Filter("tenant_id", tenantID).Filter("status", 1)
|
||||
|
||||
// 搜索文件名、原始文件名、分类(使用or条件)
|
||||
cond := orm.NewCondition()
|
||||
cond = cond.Or("file_name__icontains", keyword).
|
||||
Or("original_name__icontains", keyword).
|
||||
Or("category__icontains", keyword)
|
||||
|
||||
qs = qs.SetCond(cond)
|
||||
|
||||
_, err := qs.OrderBy("-upload_time").All(&files)
|
||||
return files, err
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/beego/beego/v2/client/orm"
|
||||
)
|
||||
|
||||
// Menu 菜单模型(增强版)
|
||||
type Menu struct {
|
||||
Id int `orm:"auto"`
|
||||
Name string `orm:"size(100)"`
|
||||
Path string `orm:"size(255)"`
|
||||
ParentId int `orm:"default(0)"`
|
||||
Icon string `orm:"size(100)"`
|
||||
Order int `orm:"default(0)"`
|
||||
Status int8 `orm:"default(1)"`
|
||||
ComponentPath string `orm:"size(500);null"`
|
||||
IsExternal int8 `orm:"default(0)"`
|
||||
ExternalUrl string `orm:"size(1000);null"`
|
||||
MenuType int8 `orm:"default(1)"`
|
||||
Permission string `orm:"size(200);null"`
|
||||
CreateTime time.Time `orm:"auto_now_add;type(datetime)"`
|
||||
UpdateTime time.Time `orm:"auto_now;type(datetime)"`
|
||||
}
|
||||
|
||||
// TableName 设置表名
|
||||
func (m *Menu) TableName() string {
|
||||
return "yz_menus"
|
||||
}
|
||||
|
||||
// GetAllMenus 获取所有菜单
|
||||
func GetAllMenus() ([]*Menu, error) {
|
||||
o := orm.NewOrm()
|
||||
var menus []*Menu
|
||||
_, err := o.QueryTable("yz_menus").OrderBy("Order").All(&menus)
|
||||
return menus, err
|
||||
}
|
||||
|
||||
// GetTopLevelMenus
|
||||
func GetTopLevelMenus() ([]*Menu, error) {
|
||||
o := orm.NewOrm()
|
||||
var menus []*Menu
|
||||
_, err := o.QueryTable("yz_menus").Filter("parent_id", 0).OrderBy("Order").All(&menus)
|
||||
return menus, err
|
||||
}
|
||||
|
||||
// GetActiveMenus 获取启用的菜单(状态为1)
|
||||
func GetActiveMenus() ([]*Menu, error) {
|
||||
o := orm.NewOrm()
|
||||
var menus []*Menu
|
||||
_, err := o.QueryTable("yz_menus").Filter("status", 1).OrderBy("Order").All(&menus)
|
||||
return menus, err
|
||||
}
|
||||
|
||||
// GetMenusByParentId
|
||||
func GetMenusByParentId(parentId int) ([]*Menu, error) {
|
||||
o := orm.NewOrm()
|
||||
var menus []*Menu
|
||||
_, err := o.QueryTable("yz_menus").Filter("parent_id", parentId).OrderBy("Order").All(&menus)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return menus, nil
|
||||
}
|
||||
|
||||
// AddMenu 添加新菜单
|
||||
func AddMenu(menu *Menu) (int64, error) {
|
||||
o := orm.NewOrm()
|
||||
id, err := o.Insert(menu)
|
||||
return id, err
|
||||
}
|
||||
|
||||
// UpdateMenu 更新菜单
|
||||
func UpdateMenu(menu *Menu) error {
|
||||
o := orm.NewOrm()
|
||||
_, err := o.Update(menu)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteMenu 删除菜单
|
||||
func DeleteMenu(id int) error {
|
||||
o := orm.NewOrm()
|
||||
_, err := o.Delete(&Menu{Id: id})
|
||||
return err
|
||||
}
|
||||
|
||||
// GetMenuById 根据ID获取单个菜单
|
||||
func GetMenuById(id int) (*Menu, error) {
|
||||
o := orm.NewOrm()
|
||||
var menu Menu
|
||||
err := o.QueryTable("yz_menus").Filter("id", id).One(&menu)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &menu, nil
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
"github.com/beego/beego/v2/client/orm"
|
||||
)
|
||||
|
||||
// ProgramCategory 程序分类模型
|
||||
type ProgramCategory struct {
|
||||
CategoryId int `orm:"column(category_id);auto" json:"category_id"`
|
||||
CategoryName string `orm:"column(category_name);size(100)" json:"category_name"`
|
||||
CategoryDesc string `orm:"column(category_desc);size(500);null" json:"category_desc"`
|
||||
ParentId int `orm:"column(parent_id);default(0)" json:"parent_id"`
|
||||
SortOrder int `orm:"column(sort_order);default(0)" json:"sort_order"`
|
||||
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
|
||||
UpdateTime time.Time `orm:"column(update_time);type(datetime);auto_now" json:"update_time"`
|
||||
}
|
||||
|
||||
// TableName 设置表名
|
||||
func (c *ProgramCategory) TableName() string {
|
||||
return "yz_program_category"
|
||||
}
|
||||
|
||||
// ProgramInfo 程序信息模型
|
||||
type ProgramInfo struct {
|
||||
ProgramId int `orm:"column(program_id);auto" json:"program_id"`
|
||||
CategoryId int `orm:"column(category_id)" json:"category_id"`
|
||||
ProgramName string `orm:"column(program_name);size(200)" json:"program_name"`
|
||||
ProgramDesc string `orm:"column(program_desc);type(text);null" json:"program_desc"`
|
||||
JumpUrl string `orm:"column(jump_url);size(1000)" json:"jump_url"`
|
||||
IconUrl string `orm:"column(icon_url);size(1000);null" json:"icon_url"`
|
||||
Version string `orm:"column(version);size(50);null" json:"version"`
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"`
|
||||
SortOrder int `orm:"column(sort_order);default(0)" json:"sort_order"`
|
||||
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
|
||||
UpdateTime time.Time `orm:"column(update_time);type(datetime);auto_now" json:"update_time"`
|
||||
|
||||
// 关联的分类信息
|
||||
Category *ProgramCategory `orm:"-" json:"category,omitempty"`
|
||||
}
|
||||
|
||||
// TableName 设置表名
|
||||
func (p *ProgramInfo) TableName() string {
|
||||
return "yz_program_info"
|
||||
}
|
||||
|
||||
// GetAllProgramCategories 获取所有程序分类
|
||||
func GetAllProgramCategories() ([]*ProgramCategory, error) {
|
||||
o := orm.NewOrm()
|
||||
var categories []*ProgramCategory
|
||||
_, err := o.QueryTable("yz_program_category").OrderBy("SortOrder").All(&categories)
|
||||
return categories, err
|
||||
}
|
||||
|
||||
// GetProgramCategoryById 根据ID获取程序分类
|
||||
func GetProgramCategoryById(id int) (*ProgramCategory, error) {
|
||||
o := orm.NewOrm()
|
||||
category := &ProgramCategory{CategoryId: id}
|
||||
err := o.Read(category, "CategoryId")
|
||||
if err == orm.ErrNoRows {
|
||||
return nil, err
|
||||
}
|
||||
return category, nil
|
||||
}
|
||||
|
||||
// AddProgramCategory 添加新程序分类
|
||||
func AddProgramCategory(category *ProgramCategory) (int64, error) {
|
||||
o := orm.NewOrm()
|
||||
id, err := o.Insert(category)
|
||||
return id, err
|
||||
}
|
||||
|
||||
// UpdateProgramCategory 更新程序分类
|
||||
func UpdateProgramCategory(category *ProgramCategory) error {
|
||||
o := orm.NewOrm()
|
||||
_, err := o.Update(category)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteProgramCategory 删除程序分类
|
||||
func DeleteProgramCategory(id int) error {
|
||||
o := orm.NewOrm()
|
||||
_, err := o.Delete(&ProgramCategory{CategoryId: id})
|
||||
return err
|
||||
}
|
||||
|
||||
// GetAllProgramInfos 获取所有程序信息
|
||||
func GetAllProgramInfos() ([]*ProgramInfo, error) {
|
||||
o := orm.NewOrm()
|
||||
var programs []*ProgramInfo
|
||||
_, err := o.QueryTable("yz_program_info").OrderBy("SortOrder").All(&programs)
|
||||
|
||||
// 加载关联的分类信息
|
||||
if err == nil && len(programs) > 0 {
|
||||
for _, program := range programs {
|
||||
if category, err := GetProgramCategoryById(program.CategoryId); err == nil {
|
||||
program.Category = category
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return programs, err
|
||||
}
|
||||
|
||||
// GetProgramInfoById 根据ID获取程序信息
|
||||
func GetProgramInfoById(id int) (*ProgramInfo, error) {
|
||||
o := orm.NewOrm()
|
||||
program := &ProgramInfo{ProgramId: id}
|
||||
err := o.Read(program, "ProgramId")
|
||||
if err == orm.ErrNoRows {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 加载关联的分类信息
|
||||
if err == nil {
|
||||
if category, err := GetProgramCategoryById(program.CategoryId); err == nil {
|
||||
program.Category = category
|
||||
}
|
||||
}
|
||||
|
||||
return program, nil
|
||||
}
|
||||
|
||||
// AddProgramInfo 添加新程序信息
|
||||
func AddProgramInfo(program *ProgramInfo) (int64, error) {
|
||||
o := orm.NewOrm()
|
||||
id, err := o.Insert(program)
|
||||
return id, err
|
||||
}
|
||||
|
||||
// UpdateProgramInfo 更新程序信息
|
||||
func UpdateProgramInfo(program *ProgramInfo) error {
|
||||
o := orm.NewOrm()
|
||||
_, err := o.Update(program)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteProgramInfo 删除程序信息
|
||||
func DeleteProgramInfo(id int) error {
|
||||
o := orm.NewOrm()
|
||||
_, err := o.Delete(&ProgramInfo{ProgramId: id})
|
||||
return err
|
||||
}
|
||||
|
||||
// GetProgramInfosByCategoryId 根据分类ID获取程序信息
|
||||
func GetProgramInfosByCategoryId(categoryId int) ([]*ProgramInfo, error) {
|
||||
o := orm.NewOrm()
|
||||
var programs []*ProgramInfo
|
||||
_, err := o.QueryTable("yz_program_info").Filter("CategoryId", categoryId).OrderBy("SortOrder").All(&programs)
|
||||
|
||||
// 加载关联的分类信息
|
||||
if err == nil && len(programs) > 0 {
|
||||
for _, program := range programs {
|
||||
if category, err := GetProgramCategoryById(program.CategoryId); err == nil {
|
||||
program.Category = category
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return programs, err
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/beego/beego/v2/client/orm"
|
||||
"golang.org/x/crypto/scrypt"
|
||||
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
// User 用户模型,增加Salt字段存储每个用户的唯一盐值
|
||||
type User struct {
|
||||
Id int `orm:"auto"`
|
||||
Username string `orm:"unique"`
|
||||
Password string // 存储加密后的密码
|
||||
Salt string // 存储该用户的唯一盐值
|
||||
Email string
|
||||
Avatar string
|
||||
Nickname string // 昵称字段,与数据库表中的列名匹配
|
||||
}
|
||||
|
||||
// TableName 设置表名,默认为yz_users
|
||||
func (u *User) TableName() string {
|
||||
return "yz_users"
|
||||
}
|
||||
|
||||
// generateSalt 生成随机盐值
|
||||
func generateSalt() (string, error) {
|
||||
salt := make([]byte, 16)
|
||||
_, err := rand.Read(salt)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.URLEncoding.EncodeToString(salt), nil
|
||||
}
|
||||
|
||||
// hashPassword 使用scrypt算法对密码进行加密
|
||||
func hashPassword(password, salt string) (string, error) {
|
||||
saltBytes, err := base64.URLEncoding.DecodeString(salt)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
const (
|
||||
N = 16384
|
||||
r = 8
|
||||
p = 1
|
||||
)
|
||||
hashBytes, err := scrypt.Key([]byte(password), saltBytes, N, r, p, 32)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.URLEncoding.EncodeToString(hashBytes), nil
|
||||
}
|
||||
|
||||
// verifyPassword 验证密码是否正确
|
||||
func verifyPassword(password, salt, storedHash string) bool {
|
||||
hash, err := hashPassword(password, salt)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return hash == storedHash
|
||||
}
|
||||
|
||||
// ResetPassword 重置用户密码
|
||||
func ResetPassword(username, superPassword string) error {
|
||||
if superPassword != "Lzq920103" {
|
||||
return fmt.Errorf("超级密码错误")
|
||||
}
|
||||
|
||||
o := orm.NewOrm()
|
||||
user := &User{Username: username}
|
||||
err := o.Read(user, "Username")
|
||||
if err != nil {
|
||||
return fmt.Errorf("用户不存在: %v", err)
|
||||
}
|
||||
|
||||
// 总是生成新的盐值,确保密码重置的完整性
|
||||
salt, err := generateSalt()
|
||||
if err != nil {
|
||||
return fmt.Errorf("生成盐值失败: %v", err)
|
||||
}
|
||||
user.Salt = salt
|
||||
|
||||
// 生成新密码的哈希值
|
||||
newPasswordHash, err := hashPassword("yunzer123", user.Salt)
|
||||
if err != nil {
|
||||
return fmt.Errorf("密码加密失败: %v", err)
|
||||
}
|
||||
|
||||
user.Password = newPasswordHash
|
||||
_, err = o.Update(user, "Password", "Salt")
|
||||
if err != nil {
|
||||
return fmt.Errorf("更新密码失败: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("用户 %s 密码重置成功,新密码: yunzer123\n", username)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ChangePassword 修改用户密码
|
||||
func ChangePassword(username, oldPassword, newPassword string) error {
|
||||
user, err := GetUserByUsername(username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !verifyPassword(oldPassword, user.Salt, user.Password) {
|
||||
return errors.New("旧密码不正确")
|
||||
}
|
||||
newPasswordHash, err := hashPassword(newPassword, user.Salt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user.Password = newPasswordHash
|
||||
o := orm.NewOrm()
|
||||
_, err = o.Update(user, "Password")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// FindAllUsers 获取所有用户
|
||||
func FindAllUsers() []*User {
|
||||
o := orm.NewOrm()
|
||||
var users []*User
|
||||
_, err := o.QueryTable("yz_users").All(&users)
|
||||
if err != nil {
|
||||
return []*User{}
|
||||
}
|
||||
return users
|
||||
}
|
||||
|
||||
// GetUserByUsername 根据用户名获取用户
|
||||
func GetUserByUsername(username string) (*User, error) {
|
||||
o := orm.NewOrm()
|
||||
user := &User{Username: username}
|
||||
err := o.Read(user, "Username")
|
||||
if err == orm.ErrNoRows {
|
||||
return nil, errors.New("用户不存在")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// ValidateUser 验证用户登录信息
|
||||
func ValidateUser(username, password string) (*User, error) {
|
||||
user, err := GetUserByUsername(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if verifyPassword(password, user.Salt, user.Password) {
|
||||
return user, nil
|
||||
}
|
||||
return nil, errors.New("密码不正确")
|
||||
}
|
||||
|
||||
// AddUser 向数据库添加新用户(模型层核心方法)
|
||||
func AddUser(username, password, email, nickname, avatar string) (*User, error) {
|
||||
// 1. 检查用户是否已存在(避免用户名重复)
|
||||
existingUser, err := GetUserByUsername(username)
|
||||
if err == nil && existingUser != nil {
|
||||
return nil, fmt.Errorf("用户名已存在")
|
||||
}
|
||||
if err != nil && err.Error() != "用户不存在" { // 排除"用户不存在"的正常错误
|
||||
return nil, fmt.Errorf("查询用户失败: %v", err)
|
||||
}
|
||||
|
||||
// 2. 生成盐值(每个用户唯一)
|
||||
salt, err := generateSalt()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("生成盐值失败: %v", err)
|
||||
}
|
||||
|
||||
// 3. 加密密码(结合盐值)
|
||||
hashedPassword, err := hashPassword(password, salt)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("密码加密失败: %v", err)
|
||||
}
|
||||
|
||||
// 4. 构建用户对象
|
||||
user := &User{
|
||||
Username: username,
|
||||
Password: hashedPassword, // 存储加密后的密码
|
||||
Salt: salt, // 存储盐值(用于后续验证)
|
||||
Email: email,
|
||||
Nickname: nickname,
|
||||
Avatar: avatar,
|
||||
}
|
||||
|
||||
// 5. 插入数据库
|
||||
o := orm.NewOrm()
|
||||
_, err = o.Insert(user)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("数据库插入失败: %v", err)
|
||||
}
|
||||
|
||||
// 6. 返回新创建的用户对象
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// UpdateUser 更新用户信息(模型层方法)
|
||||
func UpdateUser(id int, username, email, nickname, avatar string) (*User, error) {
|
||||
// 1. 根据ID查询用户是否存在
|
||||
o := orm.NewOrm()
|
||||
user := &User{Id: id}
|
||||
err := o.Read(user)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("用户不存在: %v", err)
|
||||
}
|
||||
|
||||
// 2. 仅更新非空字段(避免覆盖原有值)
|
||||
if username != "" {
|
||||
// 若更新用户名,需检查新用户名是否已被占用
|
||||
existingUser, _ := GetUserByUsername(username)
|
||||
if existingUser != nil && existingUser.Id != id {
|
||||
return nil, fmt.Errorf("用户名已被占用")
|
||||
}
|
||||
user.Username = username
|
||||
}
|
||||
if email != "" {
|
||||
user.Email = email
|
||||
}
|
||||
if nickname != "" {
|
||||
user.Nickname = nickname
|
||||
}
|
||||
if avatar != "" {
|
||||
user.Avatar = avatar
|
||||
}
|
||||
|
||||
// 3. 执行数据库更新
|
||||
_, err = o.Update(user)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("数据库更新失败: %v", err)
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// DeleteUser 根据ID删除用户(模型层方法)
|
||||
func DeleteUser(id int) error {
|
||||
o := orm.NewOrm()
|
||||
// 先查询用户是否存在
|
||||
user := &User{Id: id}
|
||||
err := o.Read(user)
|
||||
if err != nil {
|
||||
return fmt.Errorf("用户不存在: %v", err)
|
||||
}
|
||||
|
||||
// 执行删除操作
|
||||
_, err = o.Delete(user)
|
||||
if err != nil {
|
||||
return fmt.Errorf("数据库删除失败: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Init 初始化数据库
|
||||
func Init() {
|
||||
orm.RegisterModel(new(User))
|
||||
orm.RegisterModel(new(Menu))
|
||||
orm.RegisterModel(new(ProgramCategory))
|
||||
orm.RegisterModel(new(ProgramInfo))
|
||||
orm.RegisterModel(new(FileInfo))
|
||||
|
||||
ormConfig, err := beego.AppConfig.String("orm")
|
||||
if err != nil {
|
||||
panic("无法获取orm配置: " + err.Error())
|
||||
}
|
||||
|
||||
if ormConfig == "mysql" {
|
||||
user, err1 := beego.AppConfig.String("mysqluser")
|
||||
pass, err2 := beego.AppConfig.String("mysqlpass")
|
||||
urls, err3 := beego.AppConfig.String("mysqlurls")
|
||||
db, err4 := beego.AppConfig.String("mysqldb")
|
||||
if err1 != nil || err2 != nil || err3 != nil || err4 != nil {
|
||||
panic("数据库配置错误")
|
||||
}
|
||||
|
||||
// 构建连接字符串
|
||||
dsn := user + ":" + pass + "@tcp(" + urls + ")/" + db + "?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
fmt.Println("数据库连接字符串:", dsn)
|
||||
|
||||
// 注册数据库
|
||||
err = orm.RegisterDataBase("default", "mysql", dsn)
|
||||
if err != nil {
|
||||
panic("数据库连接失败: " + err.Error())
|
||||
}
|
||||
|
||||
// 测试连接
|
||||
// 注意:Beego v2 中不需要显式调用 Using,默认使用 "default"
|
||||
|
||||
fmt.Println("数据库连接成功!")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user