324 lines
10 KiB
Go
324 lines
10 KiB
Go
package model
|
||
|
||
import (
|
||
"backend/store"
|
||
"backend/util"
|
||
"fmt"
|
||
"strings"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
type Admin struct {
|
||
ID int `json:"id" db:"id"`
|
||
Username string `json:"username" db:"username"`
|
||
Password string `json:"password" db:"password"`
|
||
RealName string `json:"real_name" db:"real_name"`
|
||
Nickname string `json:"nickname" db:"nickname"`
|
||
Phone string `json:"phone" db:"phone"`
|
||
Email string `json:"email" db:"email"`
|
||
Token string `json:"token" db:"token"`
|
||
Group string `json:"group" db:"group"`
|
||
Status int `json:"status" db:"status"`
|
||
Expires int `json:"expires" db:"expires"`
|
||
Role int `json:"role" db:"role"`
|
||
LastLoginTime int `json:"lastLoginTime" db:"lastLoginTime"`
|
||
LastLoginIP string `json:"lastLoginIp" db:"lastLoginIp"`
|
||
CreateTime int `json:"createTime" db:"createTime"`
|
||
UpdateTime int `json:"updateTime" db:"updateTime"`
|
||
Remark string `json:"remark" db:"remark"`
|
||
}
|
||
|
||
type AdminLog struct {
|
||
ID int `json:"id" db:"id"`
|
||
Admin string `json:"admin" db:"admin"`
|
||
Action string `json:"action" db:"action"`
|
||
Params string `json:"params" db:"params"`
|
||
IP string `json:"ip" db:"ip"`
|
||
CreateTime int `json:"createTime" db:"createTime"`
|
||
}
|
||
|
||
func (a *Admin) List() (*Result, error) {
|
||
var admins []Admin
|
||
db := util.MPool.GetGameDB()
|
||
defer db.Close()
|
||
if db == nil {
|
||
return nil, fmt.Errorf("failed to get database connection")
|
||
}
|
||
err := db.Select(&admins, "SELECT `id`,`username`,`real_name`,`nickname`,`phone`,`email`,`group`,`status`,`role`,`lastLoginTime`,`lastLoginIp`,`createTime`,`updateTime`,`remark` FROM admin ORDER BY id DESC")
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to scan rows: %v", err)
|
||
}
|
||
var total int
|
||
db.Get(&total, "SELECT COUNT(*) FROM admin")
|
||
return &Result{
|
||
Data: admins,
|
||
Total: total,
|
||
}, nil
|
||
}
|
||
|
||
func (a *Admin) Add() (*Result, error) {
|
||
// 这里可以添加逻辑来保存管理员信息到数据库
|
||
// 假设我们将管理员信息插入到数据库中
|
||
db := util.MPool.GetGameDB() // 假设使用默认的AppConfig和ServerId为0
|
||
defer db.Close()
|
||
if db == nil {
|
||
return nil, fmt.Errorf("failed to get database connection")
|
||
}
|
||
defer db.Close()
|
||
a.CreateTime = int(util.Now())
|
||
a.UpdateTime = a.CreateTime
|
||
if a.Status == 0 {
|
||
a.Status = 1 // 默认启用
|
||
}
|
||
a.Password, _ = util.Encrypt(a.Password)
|
||
_, err := db.NamedExec("INSERT INTO admin (`username`, `password`, `real_name`, `nickname`, `phone`, `email`, `token`, `group`, `status`, `role`, `createTime`, `updateTime`, `expires`, `remark`) VALUES (:username, :password, :real_name, :nickname, :phone, :email, :token, :group, :status, :role, :createTime, :updateTime, :expires, :remark)", a)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to add admin: %v", err)
|
||
}
|
||
var total int
|
||
db.Get(&total, "SELECT COUNT(*) FROM admin")
|
||
return &Result{
|
||
Data: a,
|
||
Total: total,
|
||
}, nil
|
||
}
|
||
|
||
func (a *Admin) Login() (*Admin, error) {
|
||
// 这里可以添加逻辑来验证用户名和密码
|
||
// 假设我们从数据库中查询到管理员信息并返回
|
||
db := util.MPool.GetGameDB() // 假设使用默认的AppConfig和ServerId为0
|
||
defer db.Close()
|
||
if db == nil {
|
||
return nil, fmt.Errorf("failed to get database connection")
|
||
}
|
||
var admin Admin
|
||
err := db.Get(&admin, "SELECT * FROM admin WHERE username = ?", a.Username)
|
||
admin.Password, _ = util.Decrypt(admin.Password) // 假设有一个解密函数Login
|
||
if err != nil {
|
||
return nil, fmt.Errorf("账号不存在")
|
||
}
|
||
if admin.Password != a.Password {
|
||
return nil, fmt.Errorf("密码错误")
|
||
}
|
||
if (admin.Expires > 0 && admin.Expires < int(util.Now())) || admin.Token == "" || admin.Expires == 0 {
|
||
admin.CreateToken() // 如果令牌过期,重新生成令牌
|
||
}
|
||
return &Admin{
|
||
ID: admin.ID,
|
||
Username: admin.Username,
|
||
Token: admin.Token,
|
||
}, nil
|
||
}
|
||
|
||
func (a *Admin) LoginByCode(phone, code string) (*Admin, error) {
|
||
db := util.MPool.GetGameDB() // 假设使用默认的AppConfig和ServerId为0
|
||
defer db.Close()
|
||
if db == nil {
|
||
return nil, fmt.Errorf("failed to get database connection")
|
||
}
|
||
var admin Admin
|
||
err := db.Get(&admin, "SELECT * FROM admin WHERE phone = ?", phone)
|
||
if (admin.Expires > 0 && admin.Expires < int(util.Now())) || admin.Token == "" || admin.Expires == 0 {
|
||
admin.CreateToken() // 如果令牌过期,重新生成令牌
|
||
}
|
||
if err != nil {
|
||
return nil, fmt.Errorf("账号不存在")
|
||
}
|
||
if code == "" {
|
||
return nil, fmt.Errorf("验证码不能为空")
|
||
}
|
||
storedCode, exists := store.GetCode(phone)
|
||
if !exists || storedCode != code {
|
||
return nil, fmt.Errorf("验证码错误")
|
||
}
|
||
return &Admin{
|
||
ID: admin.ID,
|
||
Username: admin.Username,
|
||
Token: admin.Token,
|
||
}, nil
|
||
}
|
||
|
||
func (a *Admin) CreateToken() error {
|
||
// 这里可以添加逻辑来生成令牌
|
||
// 假设我们生成一个新的令牌并更新到数据库中
|
||
a.Token = util.GenerateToken() // 假设有一个生成令牌的函数
|
||
db := util.MPool.GetGameDB() // 假设使用默认的AppConfig和ServerId为0
|
||
defer db.Close()
|
||
if db == nil {
|
||
return fmt.Errorf("failed to get database connection")
|
||
}
|
||
a.Expires = int(util.Now()) + 604800
|
||
store.AddToken(a.Token, int64(a.Expires), a.Username, util.GetRole(a.Role)) // 添加到TokenList
|
||
_, err := db.NamedExec("UPDATE admin SET token = :token, expires = :expires WHERE id = :id", a)
|
||
if err != nil {
|
||
return fmt.Errorf("failed to update token: %v", err)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (a *Admin) GetAdmin(username string) error {
|
||
db := util.MPool.GetGameDB() // 假设使用默认的AppConfig和ServerId为0
|
||
defer db.Close()
|
||
if db == nil {
|
||
return fmt.Errorf("failed to get database connection")
|
||
}
|
||
return db.Get(a, "SELECT `username`, `role`, `password`, `token`, `group`, `remark` FROM admin WHERE username = ?", username)
|
||
}
|
||
|
||
func InitToken() {
|
||
// 初始化TokenList,可以从数据库中加载现有的令牌
|
||
db := util.MPool.GetGameDB() // 假设使用默认的AppConfig和ServerId为0
|
||
defer db.Close()
|
||
if db == nil {
|
||
return
|
||
}
|
||
var tokens []struct {
|
||
Token string `db:"token"`
|
||
Expires int64 `db:"expires"`
|
||
UserName string `db:"username"`
|
||
Role int `db:"role"` // 假设有一个角色字段
|
||
}
|
||
err := db.Select(&tokens, "SELECT username, token, expires, role FROM admin WHERE token IS NOT NULL")
|
||
if err != nil {
|
||
return // 处理错误
|
||
}
|
||
for _, t := range tokens {
|
||
store.AddToken(t.Token, t.Expires, t.UserName, util.GetRole(t.Role))
|
||
}
|
||
}
|
||
|
||
func (a *Admin) Edit() error {
|
||
db := util.MPool.GetGameDB()
|
||
defer db.Close()
|
||
if db == nil {
|
||
return fmt.Errorf("failed to get database connection")
|
||
}
|
||
a.UpdateTime = int(util.Now())
|
||
if a.Password != "" {
|
||
a.Password, _ = util.Encrypt(a.Password)
|
||
_, err := db.NamedExec("UPDATE admin SET `real_name`=:real_name, `nickname`=:nickname, `phone`=:phone, `email`=:email, `group`=:group, `role`=:role, `status`=:status, `remark`=:remark, `password`=:password, `updateTime`=:updateTime WHERE id=:id", a)
|
||
return err
|
||
}
|
||
_, err := db.NamedExec("UPDATE admin SET `real_name`=:real_name, `nickname`=:nickname, `phone`=:phone, `email`=:email, `group`=:group, `role`=:role, `status`=:status, `remark`=:remark, `updateTime`=:updateTime WHERE id=:id", a)
|
||
return err
|
||
}
|
||
|
||
func (a *Admin) Delete() error {
|
||
db := util.MPool.GetGameDB()
|
||
defer db.Close()
|
||
if db == nil {
|
||
return fmt.Errorf("failed to get database connection")
|
||
}
|
||
_, err := db.Exec("DELETE FROM admin WHERE id = ?", a.ID)
|
||
return err
|
||
}
|
||
|
||
func SendPhoneCode(phone string) error {
|
||
// 这里可以添加逻辑来发送验证码到手机
|
||
// 假设我们使用一个外部服务发送验证码
|
||
Code, err := util.GeneratedCode(phone) // 假设有一个发送短信的函数
|
||
store.AddCode(phone, Code) // 将验证码存储到CodeList
|
||
if err != nil {
|
||
return fmt.Errorf("failed to send code: %v", err)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// CheckUserPermission 基于 admin_permission 表进行动态 DB 鉴权。
|
||
// 鉴权优先级:super 全放行 → 路径无受控权限点放行 →
|
||
// 用户直接权限(显式允许/拒绝)→ 用户组→角色→权限链路 → 默认拒绝。
|
||
func CheckUserPermission(username, path, method string) bool {
|
||
db := util.MPool.GetGameDB()
|
||
if db == nil {
|
||
return false
|
||
}
|
||
defer db.Close()
|
||
|
||
// 查询用户 ID 和角色
|
||
var adminInfo struct {
|
||
ID int `db:"id"`
|
||
Role int `db:"role"`
|
||
}
|
||
if err := db.Get(&adminInfo, "SELECT id, role FROM admin WHERE username = ?", username); err != nil {
|
||
return false
|
||
}
|
||
|
||
// super 超级管理员跳过所有权限检查
|
||
if util.GetRole(adminInfo.Role) == util.RoleSuper {
|
||
return true
|
||
}
|
||
|
||
// 用户通过用户组继承到 R_SUPER 角色时放行
|
||
var superRoleCount int
|
||
if err := db.Get(&superRoleCount,
|
||
`SELECT COUNT(*)
|
||
FROM admin_user_group_rel ugr
|
||
INNER JOIN admin_group_role_rel grr ON grr.group_id = ugr.group_id
|
||
INNER JOIN admin_role r ON r.id = grr.role_id
|
||
WHERE ugr.admin_id = ? AND r.role_code = 'R_SUPER' AND r.status = 1`,
|
||
adminInfo.ID,
|
||
); err == nil && superRoleCount > 0 {
|
||
return true
|
||
}
|
||
|
||
// 查找匹配路径的受控权限点(http_method 为空视为不限方法)
|
||
var permIDs []int
|
||
if err := db.Select(&permIDs,
|
||
"SELECT id FROM admin_permission WHERE api_path = ? AND status = 1 AND (http_method = '' OR http_method = ?)",
|
||
path, method,
|
||
); err != nil || len(permIDs) == 0 {
|
||
// 路径未被任何权限点管控 → 放行
|
||
return true
|
||
}
|
||
|
||
// 检查用户直接权限(优先级最高)
|
||
for _, pid := range permIDs {
|
||
var grantType int
|
||
err := db.Get(&grantType,
|
||
"SELECT grant_type FROM admin_user_permission_rel WHERE admin_id = ? AND permission_id = ?",
|
||
adminInfo.ID, pid,
|
||
)
|
||
if err == nil {
|
||
if grantType == 2 {
|
||
return false // 显式拒绝
|
||
}
|
||
if grantType == 1 {
|
||
return true // 显式允许
|
||
}
|
||
}
|
||
}
|
||
|
||
// 检查 用户 → 用户组 → 角色 → 权限 链路
|
||
placeholders := make([]string, len(permIDs))
|
||
pidArgs := make([]interface{}, 1+len(permIDs))
|
||
pidArgs[0] = adminInfo.ID
|
||
for i, pid := range permIDs {
|
||
placeholders[i] = "?"
|
||
pidArgs[i+1] = pid
|
||
}
|
||
var count int
|
||
q := fmt.Sprintf(
|
||
`SELECT COUNT(*) FROM admin_role_permission_rel rpr
|
||
INNER JOIN admin_group_role_rel grr ON grr.role_id = rpr.role_id
|
||
INNER JOIN admin_user_group_rel ugr ON ugr.group_id = grr.group_id
|
||
WHERE ugr.admin_id = ? AND rpr.permission_id IN (%s)`,
|
||
strings.Join(placeholders, ","),
|
||
)
|
||
if err := db.Get(&count, q, pidArgs...); err == nil && count > 0 {
|
||
return true
|
||
}
|
||
|
||
return false
|
||
}
|
||
|
||
func GetAdminRole(c *gin.Context) (string, error) {
|
||
username := c.GetString("admin")
|
||
Admin := &Admin{}
|
||
err := Admin.GetAdmin(username)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
return util.GetRole(Admin.Role), nil
|
||
}
|