diff --git a/api/admin/v1/admin.go b/api/admin/v1/admin.go index cb340ee..9763026 100644 --- a/api/admin/v1/admin.go +++ b/api/admin/v1/admin.go @@ -3,7 +3,7 @@ package v1 import "github.com/gogf/gf/v2/frame/g" type AdminInfoReq struct { - g.Meta `path:"/admin/info" method:"get" tags:"Admin" summary:"获取管理员信息"` + g.Meta `path:"/admin/info" method:"get" tags:"Admin" summary:"(系统管理员)获取管理员信息"` } type AdminInfoRes struct { g.Meta `mime:"application/json"` diff --git a/api/auth/v1/auth.go b/api/auth/v1/auth.go index a3eae12..dbe274b 100644 --- a/api/auth/v1/auth.go +++ b/api/auth/v1/auth.go @@ -3,7 +3,7 @@ package v1 import "github.com/gogf/gf/v2/frame/g" type AdminLoginReq struct { - g.Meta `path:"/admin/login" method:"post" tags:"Admin" summary:"管理员登录"` + g.Meta `path:"/admin/login" method:"post" tags:"Admin" summary:"(系统管理员)管理员登录"` Username string `json:"username" v:"required" dc:"用户名"` Password string `json:"password" v:"required" dc:"密码"` } @@ -13,7 +13,7 @@ type AdminLoginRes struct { } type MerchantLoginReq struct { - g.Meta `path:"/merchant/login" method:"post" tags:"Merchant" summary:"商户登录"` + g.Meta `path:"/merchant/login" method:"post" tags:"Merchant" summary:"(商户管理员)商户登录"` Usernaem string `json:"username" v:"required" dc:"用户名"` Password string `json:"password" v:"required" dc:"密码"` } @@ -27,7 +27,7 @@ type MerchantRegisterRes struct { } type StoreLoginReq struct { - g.Meta `path:"/store/login" method:"post" tags:"Store" summary:"门店登录"` + g.Meta `path:"/store/login" method:"post" tags:"Store" summary:"(门店管理员)门店登录"` Username string `json:"username" v:"required" dc:"用户名"` Password string `json:"password" v:"required" dc:"密码"` } diff --git a/api/role/role.go b/api/role/role.go new file mode 100644 index 0000000..c477f0e --- /dev/null +++ b/api/role/role.go @@ -0,0 +1,19 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package role + +import ( + "context" + + "server/api/role/v1" +) + +type IRoleV1 interface { + List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error) + Create(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error) + Update(ctx context.Context, req *v1.UpdateReq) (res *v1.UpdateRes, err error) + Delete(ctx context.Context, req *v1.DeleteReq) (res *v1.DeleteRes, err error) + BatchDelete(ctx context.Context, req *v1.BatchDeleteReq) (res *v1.BatchDeleteRes, err error) +} diff --git a/api/role/v1/role.go b/api/role/v1/role.go new file mode 100644 index 0000000..2f9ad67 --- /dev/null +++ b/api/role/v1/role.go @@ -0,0 +1,67 @@ +package v1 + +import ( + "github.com/gogf/gf/v2/frame/g" +) + +// ListReq 获取角色列表请求参数 +type ListReq struct { + g.Meta `path:"/role" method:"get" tags:"Role" summary:"(系统管理员)获取角色列表"` + Page int `json:"page" dc:"页数"` + Size int `json:"size" dc:"每页数量"` + Status int `json:"status" dc:"状态:1=启用,2=禁用"` +} + +// ListRes 获取角色列表响应参数 +type ListRes struct { + List interface{} `json:"list" dc:"角色列表"` + Total int `json:"total" dc:"总数"` +} + +// CreateReq 创建角色请求参数 +type CreateReq struct { + g.Meta `path:"/role" method:"post" tags:"Role" summary:"(系统管理员)创建角色"` + Name string `json:"name" v:"required" dc:"角色名称"` + Code string `json:"code" v:"required" dc:"角色编码"` + Description string `json:"description" dc:"角色描述"` + Status int `json:"status" v:"required|in:1,2" dc:"状态:1=启用,2=禁用"` +} + +// CreateRes 创建角色响应参数 +type CreateRes struct { + Id int64 `json:"id" dc:"角色ID"` +} + +// UpdateReq 更新角色请求参数 +type UpdateReq struct { + g.Meta `path:"/role" method:"put" tags:"Role" summary:"(系统管理员)更新角色"` + Id int64 `json:"id" v:"required" dc:"角色ID"` + Name string `json:"name" v:"required" dc:"角色名称"` + Code string `json:"code" v:"required" dc:"角色编码"` + Description string `json:"description" dc:"角色描述"` + Status int `json:"status" v:"required|in:1,2" dc:"状态:1=启用,2=禁用"` +} + +// UpdateRes 更新角色响应参数 +type UpdateRes struct { + Success bool `json:"success" dc:"是否成功"` +} + +// DeleteReq 删除角色请求参数 +type DeleteReq struct { + g.Meta `path:"/role/{id}" method:"delete" tags:"Role" summary:"(系统管理员)删除角色"` + Id int64 `json:"id" in:"path" v:"required" dc:"角色ID"` +} + +// DeleteRes 删除角色响应参数 +type DeleteRes struct { + Success bool `json:"success" dc:"是否成功"` +} + +type BatchDeleteReq struct { + g.Meta `path:"/role" method:"delete" tags:"Role" summary:"(系统管理员)批量删除角色"` + Ids []int `json:"ids" v:"required" dc:"角色ID"` +} +type BatchDeleteRes struct { + Success bool `json:"success" dc:"是否成功"` +} diff --git a/api/wx/v1/wx.go b/api/wx/v1/wx.go index 4c0557a..6f99c35 100644 --- a/api/wx/v1/wx.go +++ b/api/wx/v1/wx.go @@ -3,7 +3,7 @@ package v1 import "github.com/gogf/gf/v2/frame/g" type WeChatLoginReq struct { - g.Meta `path:"/wechat/login" method:"post" tags:"WeChat" summary:"获取微信二维码登录"` + g.Meta `path:"/wechat/login" method:"post" tags:"WeChat" summary:"(用户)获取微信二维码登录"` SceneId string `json:"sceneId" v:"required" dc:"场景ID,规则:[门店id]_[6位随机字符串]"` } type WeChatLoginRes struct { @@ -35,7 +35,7 @@ type WeChatVertifyRes struct { } type WeChatPollingReq struct { - g.Meta `path:"/wechat/polling" method:"post" tags:"WeChat" summary:"微信长轮询"` + g.Meta `path:"/wechat/polling" method:"post" tags:"WeChat" summary:"(用户)微信长轮询"` SceneId string `json:"sceneId" v:"required" dc:"场景ID"` } type WeChatPollingRes struct { diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go index 3b660ea..8eb58c9 100644 --- a/internal/cmd/cmd.go +++ b/internal/cmd/cmd.go @@ -7,6 +7,7 @@ import ( "github.com/gogf/gf/v2/os/gcmd" "server/internal/controller/admin" "server/internal/controller/auth" + "server/internal/controller/role" "server/internal/controller/wx" "server/internal/middleware" ) @@ -30,6 +31,7 @@ var ( group.Middleware(middleware.Casbin) group.Bind( admin.NewV1(), + role.NewV1(), ) }) }) diff --git a/internal/consts/consts.go b/internal/consts/consts.go index ab86fed..961d35a 100644 --- a/internal/consts/consts.go +++ b/internal/consts/consts.go @@ -1,13 +1,8 @@ package consts const ( - GuestPermission = "guest" - UserPermission = "user" - AdminPermission = "admin" - MerchantPermission = "merchant" - StorePermission = "store" -) -const ( - QRCodeExpireTime = 60 - QRCodeLimitTime = 10 + UserRoleCode = "user" + AdminRoleCode = "admin" + MerchantRoleCode = "merchant" + StoreRoleCode = "store" ) diff --git a/internal/controller/role/role.go b/internal/controller/role/role.go new file mode 100644 index 0000000..6bfa15f --- /dev/null +++ b/internal/controller/role/role.go @@ -0,0 +1,5 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package role diff --git a/internal/controller/role/role_new.go b/internal/controller/role/role_new.go new file mode 100644 index 0000000..74c326d --- /dev/null +++ b/internal/controller/role/role_new.go @@ -0,0 +1,15 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package role + +import ( + "server/api/role" +) + +type ControllerV1 struct{} + +func NewV1() role.IRoleV1 { + return &ControllerV1{} +} diff --git a/internal/controller/role/role_v1_batch_delete.go b/internal/controller/role/role_v1_batch_delete.go new file mode 100644 index 0000000..a0fca9b --- /dev/null +++ b/internal/controller/role/role_v1_batch_delete.go @@ -0,0 +1,19 @@ +package role + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/role/v1" +) + +func (c *ControllerV1) BatchDelete(ctx context.Context, req *v1.BatchDeleteReq) (res *v1.BatchDeleteRes, err error) { + out, err := service.Role().BatchDelete(ctx, &model.BatchDeleteIn{Ids: req.Ids}) + if err != nil { + return nil, err + } + return &v1.BatchDeleteRes{ + Success: out.Success, + }, nil +} diff --git a/internal/controller/role/role_v1_create.go b/internal/controller/role/role_v1_create.go new file mode 100644 index 0000000..97680d9 --- /dev/null +++ b/internal/controller/role/role_v1_create.go @@ -0,0 +1,17 @@ +package role + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/role/v1" +) + +func (c *ControllerV1) Create(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error) { + out, err := service.Role().Create(ctx, &model.RoleCreateInput{Name: req.Name, Code: req.Code, Description: req.Description, Status: req.Status}) + if err != nil { + return nil, err + } + return &v1.CreateRes{Id: out.Id}, nil +} diff --git a/internal/controller/role/role_v1_delete.go b/internal/controller/role/role_v1_delete.go new file mode 100644 index 0000000..06c4769 --- /dev/null +++ b/internal/controller/role/role_v1_delete.go @@ -0,0 +1,19 @@ +package role + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/role/v1" +) + +func (c *ControllerV1) Delete(ctx context.Context, req *v1.DeleteReq) (res *v1.DeleteRes, err error) { + out, err := service.Role().Delete(ctx, &model.RoleDeleteInput{Id: req.Id}) + if err != nil { + return nil, err + } + return &v1.DeleteRes{ + Success: out.Success, + }, nil +} diff --git a/internal/controller/role/role_v1_list.go b/internal/controller/role/role_v1_list.go new file mode 100644 index 0000000..6805649 --- /dev/null +++ b/internal/controller/role/role_v1_list.go @@ -0,0 +1,20 @@ +package role + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/role/v1" +) + +func (c *ControllerV1) List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error) { + out, err := service.Role().GetRoleList(ctx, &model.RoleListInput{Page: req.Page, Size: req.Size, Status: req.Status}) + if err != nil { + return nil, err + } + return &v1.ListRes{ + List: out.List, + Total: out.Total, + }, nil +} diff --git a/internal/controller/role/role_v1_update.go b/internal/controller/role/role_v1_update.go new file mode 100644 index 0000000..ab1c5e6 --- /dev/null +++ b/internal/controller/role/role_v1_update.go @@ -0,0 +1,19 @@ +package role + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/role/v1" +) + +func (c *ControllerV1) Update(ctx context.Context, req *v1.UpdateReq) (res *v1.UpdateRes, err error) { + out, err := service.Role().Update(ctx, &model.RoleUpdateInput{Id: req.Id, Name: req.Name, Code: req.Code, Status: req.Status}) + if err != nil { + return nil, err + } + return &v1.UpdateRes{ + Success: out.Success, + }, nil +} diff --git a/internal/dao/internal/admins.go b/internal/dao/internal/admins.go index 290e504..7c3f2be 100644 --- a/internal/dao/internal/admins.go +++ b/internal/dao/internal/admins.go @@ -21,6 +21,7 @@ type AdminsDao struct { // AdminsColumns defines and stores column names for the table admins. type AdminsColumns struct { Id string // 管理员ID + RoleId string // 角色ID Username string // 管理员用户名 PasswordHash string // 密码哈希 RealName string // 真实姓名 @@ -35,6 +36,7 @@ type AdminsColumns struct { // adminsColumns holds the columns for the table admins. var adminsColumns = AdminsColumns{ Id: "id", + RoleId: "role_id", Username: "username", PasswordHash: "password_hash", RealName: "real_name", diff --git a/internal/dao/internal/roles.go b/internal/dao/internal/roles.go index f23a75d..c8c80b4 100644 --- a/internal/dao/internal/roles.go +++ b/internal/dao/internal/roles.go @@ -28,6 +28,7 @@ type RolesColumns struct { CreatedAt string // 创建时间 UpdatedAt string // 更新时间 DeletedAt string // 软删除时间戳 + IsDeletable string // 是否可删除:0=不可删除,1=可删除 } // rolesColumns holds the columns for the table roles. @@ -40,6 +41,7 @@ var rolesColumns = RolesColumns{ CreatedAt: "created_at", UpdatedAt: "updated_at", DeletedAt: "deleted_at", + IsDeletable: "is_deletable", } // NewRolesDao creates and returns a new DAO object for table data access. diff --git a/internal/dao/internal/users.go b/internal/dao/internal/users.go index 0c18daa..448ffe6 100644 --- a/internal/dao/internal/users.go +++ b/internal/dao/internal/users.go @@ -35,6 +35,7 @@ type UsersColumns struct { CreatedAt string // 创建时间 UpdatedAt string // 更新时间 DeletedAt string // 软删除时间 + RoleId string // 角色ID } // usersColumns holds the columns for the table users. @@ -54,6 +55,7 @@ var usersColumns = UsersColumns{ CreatedAt: "created_at", UpdatedAt: "updated_at", DeletedAt: "deleted_at", + RoleId: "role_id", } // NewUsersDao creates and returns a new DAO object for table data access. diff --git a/internal/logic/admin/admin.go b/internal/logic/admin/admin.go index 3e2be3f..48c4378 100644 --- a/internal/logic/admin/admin.go +++ b/internal/logic/admin/admin.go @@ -2,6 +2,7 @@ package admin import ( "context" + "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/os/glog" "server/internal/consts" "server/internal/dao" @@ -23,20 +24,53 @@ func New() service.IAdmin { func checkAdmin() { ctx := context.Background() - exist, err := dao.Admins.Ctx(ctx).Where(do.Admins{Username: "admin"}).Exist() - if err != nil { - panic("初始化管理员失败") - } - if !exist { - passwordHash, _ := utility.EncryptPassword("Aa123456") - _, err = dao.Admins.Ctx(ctx).Insert(do.Admins{ - Username: "admin", - PasswordHash: passwordHash, - Status: 1, - }) + + if err := dao.Roles.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { + // 检查角色是否存在 + exist, err := tx.Model(dao.Roles.Table()).Where(do.Roles{Code: consts.AdminRoleCode}).Exist() if err != nil { - panic("初始化管理员失败") + return err } + var roleId int64 + if !exist { + roleId, err = tx.Model(dao.Roles.Table()).InsertAndGetId(do.Roles{ + Name: "系统管理员", + Code: consts.AdminRoleCode, + Description: "管理员角色", + Status: 1, + IsDeletable: false, + }) + } else { + value, err := tx.Model(dao.Roles.Table()).Where(do.Roles{Code: consts.AdminRoleCode}).Fields(dao.Roles.Columns().Id).Value() + if err != nil { + return err + } + roleId = value.Int64() + } + + // 检查管理员是否存在 + exist, err = tx.Model(dao.Admins.Table()).Where(do.Admins{Username: "admin"}).Exist() + if err != nil { + return err + } + if !exist { + password, err := utility.EncryptPassword("Aa123456") + if err != nil { + return err + } + _, err = tx.Model(dao.Admins.Table()).InsertAndGetId(do.Admins{ + Username: "admin", + PasswordHash: password, + RoleId: roleId, + Status: 1, + }) + if err != nil { + return err + } + } + return nil + }); err != nil { + panic("初始化系统失败") } glog.Infof(ctx, "初始化管理员成功") } @@ -60,7 +94,11 @@ func (s *sAdmin) Login(ctx context.Context, in *model.AdminLoginIn) (out *model. if !utility.ComparePassword(admin.PasswordHash, in.Password) { return nil, ecode.Auth } - token, err := jwt.GenerateToken(&jwt.TokenIn{UserId: admin.Id, Permission: consts.AdminPermission}) + value, err := dao.Roles.Ctx(ctx).WherePri(admin.RoleId).Fields(dao.Roles.Columns().Code).Value() + if err != nil { + return nil, ecode.Fail.Sub("查询角色失败") + } + token, err := jwt.GenerateToken(&jwt.TokenIn{UserId: admin.Id, Role: value.String()}) if err != nil { return nil, ecode.Fail.Sub("生成token失败") } @@ -84,6 +122,7 @@ func (s *sAdmin) Info(ctx context.Context, in *model.AdminInfoIn) (out *model.Ad return nil, ecode.Fail.Sub("查询管理员失败") } out = &model.AdminInfoOut{ + Id: admin.Id, Username: admin.Username, } return diff --git a/internal/logic/logic.go b/internal/logic/logic.go index cdd1ee2..2439c05 100644 --- a/internal/logic/logic.go +++ b/internal/logic/logic.go @@ -7,6 +7,7 @@ package logic import ( _ "server/internal/logic/admin" _ "server/internal/logic/merchantAdmin" + _ "server/internal/logic/role" _ "server/internal/logic/storeAdmin" _ "server/internal/logic/user" ) diff --git a/internal/logic/role/role.go b/internal/logic/role/role.go new file mode 100644 index 0000000..afef2da --- /dev/null +++ b/internal/logic/role/role.go @@ -0,0 +1,162 @@ +package role + +import ( + "context" + "server/internal/dao" + "server/internal/model" + "server/internal/model/do" + "server/internal/service" + "server/utility/ecode" + + "github.com/gogf/gf/v2/database/gdb" +) + +type sRole struct { +} + +func New() service.IRole { + return &sRole{} +} + +func init() { + service.RegisterRole(New()) +} + +func (s *sRole) Create(ctx context.Context, in *model.RoleCreateInput) (out *model.CreateOut, err error) { + // 检查角色编码是否已存在 + exist, err := dao.Roles.Ctx(ctx).Where(do.Roles{Code: in.Code}).Exist() + if err != nil { + return nil, ecode.Fail.Sub("新增角色查重出现异常") + } + if exist { + return nil, ecode.Params.Sub("角色编码已存在") + } + + // 创建角色 + id, err := dao.Roles.Ctx(ctx).InsertAndGetId(do.Roles{ + Name: in.Name, + Code: in.Code, + Description: in.Description, + Status: in.Status, + IsDeletable: true, + }) + if err != nil { + return nil, ecode.Fail.Sub("创建角色失败") + } + return &model.CreateOut{Id: id}, nil +} + +func (s *sRole) Delete(ctx context.Context, in *model.RoleDeleteInput) (out *model.DeleteOut, err error) { + // 检查角色是否存在且可删除 + role, err := dao.Roles.Ctx(ctx).WherePri(in.Id).One() + if err != nil { + return nil, ecode.Fail.Sub("查询角色失败") + } + if role.IsEmpty() { + return nil, ecode.Params.Sub("角色不存在") + } + + if !role["is_deletable"].Bool() { + return nil, ecode.Params.Sub("该角色不可删除") + } + + if err = dao.Roles.Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) { + // 删除角色 + if _, err = dao.Roles.Ctx(ctx).Where(do.Roles{Id: in.Id}).Delete(); err != nil { + err = ecode.Fail.Sub("删除角色失败") + } + // TODO : 删除角色后续需要处理的操作 + return + }); err != nil { + return nil, err + } + return &model.DeleteOut{Success: true}, nil +} + +func (s *sRole) BatchDelete(ctx context.Context, in *model.BatchDeleteIn) (out *model.DeleteOut, err error) { + + // 检查角色是否存在且可删除 + roles, err := dao.Roles.Ctx(ctx).WhereIn(dao.Roles.Columns().Id, in.Ids).All() + if err != nil { + return nil, ecode.Fail.Sub("查询角色失败") + } + if len(roles) == 0 { + return nil, ecode.Params.Sub("角色不存在") + } + + // 检查是否有不可删除的角色 + for _, role := range roles { + if !role["is_deletable"].Bool() { + return nil, ecode.Params.Sub("存在不可删除的角色") + } + } + + // 开启事务 + if err = dao.Roles.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { + // 删除角色 + if _, err = dao.Roles.Ctx(ctx).WhereIn(dao.Roles.Columns().Id, in.Ids).Delete(); err != nil { + return ecode.Fail.Sub("删除角色失败") + } + // TODO : 删除角色后续需要处理的操作 + return nil + }); err != nil { + return nil, err + } + return &model.DeleteOut{Success: true}, nil +} + +func (s *sRole) Update(ctx context.Context, in *model.RoleUpdateInput) (out *model.UpdateOut, err error) { + // 检查角色是否存在 + exist, err := dao.Roles.Ctx(ctx).Where(do.Roles{Id: in.Id}).Exist() + if err != nil { + return nil, ecode.Fail.Sub("查询角色失败") + } + if !exist { + return nil, ecode.Params.Sub("角色不存在") + } + + // 检查角色编码是否已存在(排除自身) + exist, err = dao.Roles.Ctx(ctx). + Where(do.Roles{Code: in.Code}). + WhereNot(dao.Roles.Columns().Id, in.Id). + Exist() + if err != nil { + return nil, ecode.Fail.Sub("查询角色编码失败") + } + if exist { + return nil, ecode.Params.Sub("角色编码已存在") + } + + // 更新角色 + if _, err = dao.Roles.Ctx(ctx). + Where(do.Roles{Id: in.Id}). + Update(do.Roles{ + Name: in.Name, + Code: in.Code, + Description: in.Description, + Status: in.Status, + }); err != nil { + return nil, ecode.Fail.Sub("更新角色失败") + } + + return &model.UpdateOut{Success: true}, nil +} + +func (s *sRole) GetRoleList(ctx context.Context, in *model.RoleListInput) (out *model.RoleListOutput, err error) { + list := make([]model.Role, 0) + var total int + // 构建查询条件 + orm := dao.Roles.Ctx(ctx) + if in.Status > 0 { + orm = orm.Where(dao.Roles.Columns().Status, in.Status) + } + + // 获取分页数据 + if err = orm.Page(in.Page, in.Size).ScanAndCount(&list, &total, false); err != nil { + return nil, ecode.Fail.Sub("查询角色列表失败") + } + return &model.RoleListOutput{ + List: list, + Total: total, + }, nil +} diff --git a/internal/logic/user/user.go b/internal/logic/user/user.go index 371985d..0399a18 100644 --- a/internal/logic/user/user.go +++ b/internal/logic/user/user.go @@ -19,6 +19,27 @@ type sUser struct{} func init() { service.RegisterUser(New()) + go checkUserRole() +} + +func checkUserRole() { + ctx := context.Background() + exist, err := dao.Roles.Ctx(ctx).Where(do.Roles{Code: consts.UserRoleCode}).Exist() + if err != nil { + return + } + if !exist { + _, err := dao.Roles.Ctx(ctx).Data(do.Roles{ + Name: "用户", + Code: consts.UserRoleCode, + Description: "用户角色", + Status: 1, + IsDeletable: false, + }).Insert() + if err != nil { + return + } + } } func New() service.IUser { @@ -26,12 +47,15 @@ func New() service.IUser { } func (s *sUser) Login(ctx context.Context, in *model.UserLoginIn) (out *model.UserLoginOut, err error) { + value, err := dao.Roles.Ctx(ctx).Where(do.Roles{Code: consts.UserRoleCode}).Fields(dao.Roles.Columns().Code).Value() + if err != nil { + return nil, ecode.Fail.Sub("查找角色失败") + } // 根据 OpenId 查找用户 exist, err := dao.Users.Ctx(ctx).Where(do.Users{WxOpenId: in.OpenId}).Exist() if err != nil { return nil, ecode.Fail.Sub("查找用户失败") } - var userId int64 if !exist { // 用户不存在,创建新用户 @@ -62,8 +86,8 @@ func (s *sUser) Login(ctx context.Context, in *model.UserLoginIn) (out *model.Us // 生成 token token, err := jwt.GenerateToken(&jwt.TokenIn{ - UserId: userId, - Permission: consts.UserPermission, + UserId: userId, + Role: value.String(), }) if err != nil { return nil, ecode.Fail.Sub("生成token失败") diff --git a/internal/middleware/auth.go b/internal/middleware/auth.go index 2c30da6..8c8c86a 100644 --- a/internal/middleware/auth.go +++ b/internal/middleware/auth.go @@ -41,7 +41,7 @@ func Auth(r *ghttp.Request) { Exit(r, err) } r.SetCtxVar("userId", tokenOut.UserId) - r.SetCtxVar("permission", tokenOut.Permission) + r.SetCtxVar("role", tokenOut.Role) r.SetCtxVar("jti", tokenOut.JTI) } r.Middleware.Next() diff --git a/internal/middleware/casbin.go b/internal/middleware/casbin.go index 6cd3f56..7e74ba1 100644 --- a/internal/middleware/casbin.go +++ b/internal/middleware/casbin.go @@ -19,8 +19,8 @@ import ( // - 如果权限验证未通过:终止请求,返回权限不足的错误(ecode.Denied)。 // - 如果权限验证通过:继续执行后续中间件或处理逻辑。 func Casbin(r *ghttp.Request) { - permission := r.GetCtxVar("permission").String() - if !myCasbin.GetMyCasbin().HasPermission(permission, r.URL.Path, r.Method) { + role := r.GetCtxVar("role").String() + if !myCasbin.GetMyCasbin().HasPermission(role, r.URL.Path, r.Method) { Exit(r, ecode.Denied) } r.Middleware.Next() diff --git a/internal/model/admin.go b/internal/model/admin.go index 2e1b7a1..b47ac75 100644 --- a/internal/model/admin.go +++ b/internal/model/admin.go @@ -10,6 +10,7 @@ type ( Id int } AdminInfoOut struct { + Id int64 Username string } ) diff --git a/internal/model/common.go b/internal/model/common.go index 417a80a..dbbd51f 100644 --- a/internal/model/common.go +++ b/internal/model/common.go @@ -1,5 +1,8 @@ package model +type BatchDeleteIn struct { + Ids []int +} type LoginOut struct { Token string } diff --git a/internal/model/do/admins.go b/internal/model/do/admins.go index 339245d..4849eac 100644 --- a/internal/model/do/admins.go +++ b/internal/model/do/admins.go @@ -13,6 +13,7 @@ import ( type Admins struct { g.Meta `orm:"table:admins, do:true"` Id interface{} // 管理员ID + RoleId interface{} // 角色ID Username interface{} // 管理员用户名 PasswordHash interface{} // 密码哈希 RealName interface{} // 真实姓名 diff --git a/internal/model/do/roles.go b/internal/model/do/roles.go index 42e24bd..f2a347f 100644 --- a/internal/model/do/roles.go +++ b/internal/model/do/roles.go @@ -20,4 +20,5 @@ type Roles struct { CreatedAt *gtime.Time // 创建时间 UpdatedAt *gtime.Time // 更新时间 DeletedAt *gtime.Time // 软删除时间戳 + IsDeletable interface{} // 是否可删除:0=不可删除,1=可删除 } diff --git a/internal/model/do/users.go b/internal/model/do/users.go index 10c510b..f6661e8 100644 --- a/internal/model/do/users.go +++ b/internal/model/do/users.go @@ -27,4 +27,5 @@ type Users struct { CreatedAt *gtime.Time // 创建时间 UpdatedAt *gtime.Time // 更新时间 DeletedAt *gtime.Time // 软删除时间 + RoleId interface{} // 角色ID } diff --git a/internal/model/entity/admins.go b/internal/model/entity/admins.go index 6b638b1..89eaa0e 100644 --- a/internal/model/entity/admins.go +++ b/internal/model/entity/admins.go @@ -11,6 +11,7 @@ import ( // Admins is the golang structure for table admins. type Admins struct { Id int64 `json:"id" orm:"id" description:"管理员ID"` // 管理员ID + RoleId int64 `json:"roleId" orm:"role_id" description:"角色ID"` // 角色ID Username string `json:"username" orm:"username" description:"管理员用户名"` // 管理员用户名 PasswordHash string `json:"passwordHash" orm:"password_hash" description:"密码哈希"` // 密码哈希 RealName string `json:"realName" orm:"real_name" description:"真实姓名"` // 真实姓名 diff --git a/internal/model/entity/roles.go b/internal/model/entity/roles.go index 68d1166..b473ed3 100644 --- a/internal/model/entity/roles.go +++ b/internal/model/entity/roles.go @@ -10,12 +10,13 @@ import ( // Roles is the golang structure for table roles. type Roles struct { - Id int64 `json:"id" orm:"id" description:"角色ID"` // 角色ID - Name string `json:"name" orm:"name" description:"角色名称"` // 角色名称 - Code string `json:"code" orm:"code" description:"角色编码"` // 角色编码 - Description string `json:"description" orm:"description" description:"角色描述"` // 角色描述 - Status int `json:"status" orm:"status" description:"状态:1=启用,2=禁用"` // 状态:1=启用,2=禁用 - CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间 - UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间 - DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳 + Id int64 `json:"id" orm:"id" description:"角色ID"` // 角色ID + Name string `json:"name" orm:"name" description:"角色名称"` // 角色名称 + Code string `json:"code" orm:"code" description:"角色编码"` // 角色编码 + Description string `json:"description" orm:"description" description:"角色描述"` // 角色描述 + Status int `json:"status" orm:"status" description:"状态:1=启用,2=禁用"` // 状态:1=启用,2=禁用 + CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间 + UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间 + DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳 + IsDeletable bool `json:"isDeletable" orm:"is_deletable" description:"是否可删除:0=不可删除,1=可删除"` // 是否可删除:0=不可删除,1=可删除 } diff --git a/internal/model/entity/users.go b/internal/model/entity/users.go index 406a22f..3aaf380 100644 --- a/internal/model/entity/users.go +++ b/internal/model/entity/users.go @@ -25,4 +25,5 @@ type Users struct { CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间 UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间 DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间"` // 软删除时间 + RoleId int64 `json:"roleId" orm:"role_id" description:"角色ID"` // 角色ID } diff --git a/internal/model/role.go b/internal/model/role.go new file mode 100644 index 0000000..311856f --- /dev/null +++ b/internal/model/role.go @@ -0,0 +1,54 @@ +package model + +import "github.com/gogf/gf/v2/frame/g" + +// Role 角色信息 +type Role struct { + g.Meta `orm:"table:roles"` + Id int64 `json:"id" dc:"角色ID" orm:"id"` + Name string `json:"name" dc:"角色名称" orm:"name"` + Code string `json:"code" dc:"角色编码" orm:"code"` + Description string `json:"description" dc:"角色描述" orm:"description"` + Status int `json:"status" dc:"状态:1=启用,2=禁用" orm:"status"` + IsDeletable bool `json:"is_deletable" dc:"是否可删除:0=不可删除,1=可删除" orm:"is_deletable"` +} + +// RoleCreateInput 创建角色输入参数 +type RoleCreateInput struct { + Name string + Code string + Description string + Status int +} + +// RoleUpdateInput 更新角色输入参数 +type RoleUpdateInput struct { + Id int64 + Name string + Code string + Description string + Status int +} + +// RoleListInput 获取角色列表输入参数 +type RoleListInput struct { + Page int + Size int + Status int +} + +// RoleListOutput 获取角色列表输出参数 +type RoleListOutput struct { + List []Role + Total int +} + +// RoleGetByIdInput 根据ID获取角色输入参数 +type RoleGetByIdInput struct { + Id int64 +} + +// RoleDeleteInput 删除角色输入参数 +type RoleDeleteInput struct { + Id int64 +} diff --git a/internal/service/role.go b/internal/service/role.go new file mode 100644 index 0000000..306d34e --- /dev/null +++ b/internal/service/role.go @@ -0,0 +1,36 @@ +// ================================================================================ +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "server/internal/model" +) + +type ( + IRole interface { + Create(ctx context.Context, in *model.RoleCreateInput) (out *model.CreateOut, err error) + Delete(ctx context.Context, in *model.RoleDeleteInput) (out *model.DeleteOut, err error) + BatchDelete(ctx context.Context, in *model.BatchDeleteIn) (out *model.DeleteOut, err error) + Update(ctx context.Context, in *model.RoleUpdateInput) (out *model.UpdateOut, err error) + GetRoleList(ctx context.Context, in *model.RoleListInput) (out *model.RoleListOutput, err error) + } +) + +var ( + localRole IRole +) + +func Role() IRole { + if localRole == nil { + panic("implement not found for interface IRole, forgot register?") + } + return localRole +} + +func RegisterRole(i IRole) { + localRole = i +} diff --git a/utility/jwt/jwt.go b/utility/jwt/jwt.go index 7df8495..a096a0d 100644 --- a/utility/jwt/jwt.go +++ b/utility/jwt/jwt.go @@ -22,11 +22,11 @@ type ( // // 字段: // - UserId: 用户 ID; - // - Permission: 权限标识; + // - Role: 权限标识; // - ExpireTime: token 过期时间(可选)。 TokenIn struct { UserId int64 // 用户 ID - Permission string // 权限标识 + Role string // 权限标识 ExpireTime time.Duration // 令牌有效期 } @@ -34,19 +34,19 @@ type ( // // 字段: // - UserId: 用户 ID; - // - Permission: 权限标识; + // - Role: 权限标识; // - JTI: JWT 的唯一标识。 TokenOut struct { - UserId int64 // 用户 ID - Permission string // 权限标识 - JTI string // JWT 唯一标识 + UserId int64 // 用户 ID + Role string // 权限标识 + JTI string // JWT 唯一标识 } // jwtClaims 自定义 JWT 的声明体结构,嵌入标准声明字段。 jwtClaims struct { - UserId int64 `json:"user_id"` // 用户 ID - Permission string `json:"permission"` // 权限标识 - JTI string `json:"jti"` // 唯一标识 + UserId int64 `json:"user_id"` // 用户 ID + Role string `json:"Role"` // 权限标识 + JTI string `json:"jti"` // 唯一标识 jwt.RegisteredClaims } ) @@ -66,9 +66,9 @@ func GenerateToken(in *TokenIn) (string, error) { } claims := jwtClaims{ - UserId: in.UserId, - Permission: in.Permission, - JTI: uuid.NewString(), + UserId: in.UserId, + Role: in.Role, + JTI: uuid.NewString(), RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(expire)), IssuedAt: jwt.NewNumericDate(time.Now()), @@ -108,8 +108,8 @@ func ParseToken(tokenString string) (*TokenOut, error) { } return &TokenOut{ - UserId: claims.UserId, - Permission: claims.Permission, - JTI: claims.JTI, + UserId: claims.UserId, + Role: claims.Role, + JTI: claims.JTI, }, nil } diff --git a/utility/myCasbin/casbin.go b/utility/myCasbin/casbin.go index a365eaf..7124f7a 100644 --- a/utility/myCasbin/casbin.go +++ b/utility/myCasbin/casbin.go @@ -33,8 +33,18 @@ func init() { } enforcer.LoadPolicy() + // 管理员 { + // admin enforcer.AddPolicy("admin", "/x/admin/info", "GET", "获取管理员用户信息") + + // role + enforcer.AddPolicy("admin", "/x/role", "GET", "管理员获取角色列表") + enforcer.AddPolicy("admin", "/x/role", "POST", "管理员添加角色") + enforcer.AddPolicy("admin", "/x/role", "PUT", "管理员更新角色") + enforcer.AddPolicy("admin", "/x/role", "DELETE", "管理员给角色分配权限") + enforcer.AddPolicy("admin", "/x/role/*", "DELETE", "管理员删除单个角色") + } instance = &myCasbin{Enforcer: enforcer}