fix 修改验证码为点击验证,角色改为树形结构,代码生成权限bug修复

This commit is contained in:
yxh 2023-12-25 12:01:44 +08:00
parent 043d0e6ea9
commit 48823c37a2
21 changed files with 300 additions and 22246 deletions

View File

@ -7,13 +7,37 @@
package common
import "github.com/gogf/gf/v2/frame/g"
import (
"github.com/gogf/gf/v2/frame/g"
)
type CaptchaReq struct {
g.Meta `path:"/get" tags:"验证码" method:"get" summary:"获取验证码"`
}
type CaptchaV2Req struct {
g.Meta `path:"/v2" tags:"验证码" method:"get" summary:"获取v2验证码"`
}
type CheckCaptchaV2Req struct {
g.Meta `path:"/v2Check" tags:"验证码" method:"post" summary:"检查v2验证码"`
Key string `json:"key"`
Dots string `json:"dots"`
}
type CaptchaRes struct {
g.Meta `mime:"application/json"`
Key string `json:"key"`
Img string `json:"img"`
}
type CaptchaV2Res struct {
g.Meta `mime:"application/json"`
Key string `json:"key"`
Img string `json:"img"`
Thumb string `json:"thumb"`
}
type CheckCaptchaV2Res struct {
g.Meta `mime:"application/json"`
}

View File

@ -40,6 +40,7 @@ type RoleGetParamsRes struct {
type RoleAddReq struct {
g.Meta `path:"/role/add" tags:"角色管理" method:"post" summary:"添加角色"`
Pid uint `p:"pid"`
Name string `p:"name" v:"required#角色名称不能为空"`
Status uint `p:"status" `
ListOrder uint `p:"listOrder" `
@ -67,6 +68,7 @@ type RoleEditReq struct {
g.Meta `path:"/role/edit" tags:"角色管理" method:"put" summary:"修改角色"`
commonApi.Author
Id int64 `p:"id" v:"required#角色id必须"`
Pid uint `p:"pid"`
Name string `p:"name" v:"required#角色名称不能为空"`
Status uint `p:"status" `
ListOrder uint `p:"listOrder" `

1
go.mod
View File

@ -21,6 +21,7 @@ require (
github.com/tencentyun/cos-go-sdk-v5 v0.7.34
github.com/tiger1103/gfast-cache v1.0.2
github.com/tiger1103/gfast-token v1.0.4
github.com/wenlng/go-captcha v1.2.5
github.com/xuri/excelize/v2 v2.7.1
golang.org/x/tools v0.6.0
)

3
go.sum
View File

@ -201,6 +201,8 @@ github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+Kd
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
github.com/wenlng/go-captcha v1.2.5 h1:zA0/fovEl9oAhSg+KwHBwmq99GeeAXknWx6wYKjhjTg=
github.com/wenlng/go-captcha v1.2.5/go.mod h1:QgPgpEURSa37gF3GtojNoNRwbMwuatSBx5NXrzASOb0=
github.com/xuri/efp v0.0.0-20220603152613-6918739fd470/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca h1:uvPMDVyP7PXMMioYdyPH+0O+Ta/UO1WFfNYMO3Wz0eg=
github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
@ -239,6 +241,7 @@ golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI=
golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=

View File

@ -9,8 +9,10 @@ package controller
import (
"context"
"errors"
"github.com/tiger1103/gfast/v3/api/v1/common"
"github.com/tiger1103/gfast/v3/internal/app/common/service"
"time"
)
var Captcha = captchaController{}
@ -20,13 +22,31 @@ type captchaController struct {
// Get 获取验证码
func (c *captchaController) Get(ctx context.Context, req *common.CaptchaReq) (res *common.CaptchaRes, err error) {
var (
idKeyC, base64stringC string
)
idKeyC, base64stringC, err = service.Captcha().GetVerifyImgString(ctx)
idKeyC, base64stringC, err := service.Captcha().GetVerifyImgString(ctx)
res = &common.CaptchaRes{
Key: idKeyC,
Img: base64stringC,
}
return
}
// V2 验证码
func (c *captchaController) V2(ctx context.Context, req *common.CaptchaV2Req) (res *common.CaptchaV2Res, err error) {
dots, img, thumb, key, err := service.Captcha().GetCaptchaV2(ctx)
// 写入缓存
service.Cache().Set(ctx, "captchaV2_"+key, dots, 10*60*time.Second)
res = &common.CaptchaV2Res{
Key: key,
Img: img,
Thumb: thumb,
}
return
}
func (c *captchaController) V2Check(ctx context.Context, req *common.CheckCaptchaV2Req) (res *common.CheckCaptchaV2Res, err error) {
if req.Key == "" || req.Dots == "" {
return nil, errors.New("验证码无效")
}
err = service.Captcha().CheckCaptchaV2(ctx, req.Key, req.Dots)
return
}

View File

@ -9,16 +9,22 @@ package captcha
import (
"context"
"errors"
"github.com/gogf/gf/v2/encoding/gbase64"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"github.com/mojocn/base64Captcha"
"github.com/tiger1103/gfast/v3/internal/app/common/service"
captchaV2 "github.com/wenlng/go-captcha/captcha"
"net/url"
)
func init() {
service.RegisterCaptcha(New())
}
func New() service.ICaptcha {
func New() *sCaptcha {
return &sCaptcha{
driver: &base64Captcha.DriverString{
Height: 80,
@ -38,6 +44,63 @@ type sCaptcha struct {
store base64Captcha.Store
}
// GetCaptchaV2 创建点击验证码数据
func (s *sCaptcha) GetCaptchaV2(ctx context.Context) (dots map[int]captchaV2.CharDot, img, thumb, key string, err error) {
capt := captchaV2.GetCaptcha()
dots, img, thumb, key, err = capt.Generate()
return
}
// CheckCaptchaV2 验证captchaV2数据
func (s *sCaptcha) CheckCaptchaV2(ctx context.Context, key string, dots string, removeKey ...bool) (err error) {
dotsStr, err := gbase64.DecodeToString(dots)
if err != nil {
return err
}
// 进行Url转码防止特殊字符问题
dotsStr, err = url.QueryUnescape(dotsStr)
dotsMap := gconv.Maps(dotsStr)
if dotsMap == nil {
return errors.New("提交的数据无效")
}
cacheDots := service.Cache().Get(ctx, "captchaV2_"+key)
if cacheDots == nil {
return errors.New("未找到验证数据")
}
var dotsMap2 map[int]captchaV2.CharDot
err = cacheDots.Scan(&dotsMap2)
if len(dotsMap) != len(dotsMap2) {
return errors.New("人机验证失败")
}
g.Log().Info(ctx, dotsMap, dotsMap2)
for i, dot := range dotsMap {
checkStatus := captchaV2.CheckPointDistWithPadding(gconv.Int64(dot["x"]), gconv.Int64(dot["y"]), int64(dotsMap2[i].Dx), int64(dotsMap2[i].Dy), int64(dotsMap2[i].Width), int64(dotsMap2[i].Height), 10)
if checkStatus == false {
return errors.New("人机验证失败")
}
}
if len(removeKey) > 0 && removeKey[0] {
service.Cache().Remove(ctx, "captchaV2_"+key)
}
return
}
var (
captcha = sCaptcha{
driver: &base64Captcha.DriverString{
Height: 80,
Width: 240,
NoiseCount: 50,
ShowLineOptions: 20,
Length: 4,
Source: "abcdefghjkmnpqrstuvwxyz23456789",
Fonts: []string{"chromohv.ttf"},
},
store: base64Captcha.DefaultMemStore,
}
)
// GetVerifyImgString 获取字母数字混合验证码
func (s *sCaptcha) GetVerifyImgString(ctx context.Context) (idKeyC string, base64stringC string, err error) {
driver := s.driver.ConvertFonts()

View File

@ -7,11 +7,14 @@ package service
import (
"context"
"github.com/wenlng/go-captcha/captcha"
)
type ICaptcha interface {
GetVerifyImgString(ctx context.Context) (idKeyC string, base64stringC string, err error)
VerifyString(id, answer string) bool
GetCaptchaV2(ctx context.Context) (dots map[int]captcha.CharDot,img,thumb,key string,err error)
CheckCaptchaV2(ctx context.Context,key string,dots string,removeKey... bool) (err error)
}
var localCaptcha ICaptcha

View File

@ -40,8 +40,15 @@ func (c *loginController) Login(ctx context.Context, req *system.UserLoginReq) (
//判断验证码是否正确
debug := gmode.IsDevelop()
if !debug {
if !commonService.Captcha().VerifyString(req.VerifyKey, req.VerifyCode) {
err = gerror.New("验证码输入错误")
// 验证码v1版
//if !commonService.Captcha().VerifyString(req.VerifyKey, req.VerifyCode) {
// err = gerror.New("验证码输入错误")
// return
//}
// 验证码v2版
err = commonService.Captcha().CheckCaptchaV2(ctx, req.VerifyKey, req.VerifyCode, true)
if err != nil {
return
}
}
@ -77,7 +84,6 @@ func (c *loginController) Login(ctx context.Context, req *system.UserLoginReq) (
if g.Cfg().MustGet(ctx, "gfToken.multiLogin").Bool() {
key = gconv.String(user.Id) + "-" + gmd5.MustEncryptString(user.UserName) + gmd5.MustEncryptString(user.UserPassword+ip+userAgent)
}
user.UserPassword = ""
token, err = service.GfToken().GenerateToken(ctx, key, user)
if err != nil {
g.Log().Error(ctx, err)

View File

@ -59,10 +59,6 @@ func (c *userController) GetParams(ctx context.Context, req *system.UserGetParam
return
}
userId := service.Context().GetUserId(ctx)
res.RoleAccess, err = service.SysUser().GetAdminRoleIds(ctx, userId)
if err != nil {
return
}
//判断是否超管
if service.SysUser().IsSupperAdmin(ctx, userId) {
//自己创建的角色可以被授权
@ -70,7 +66,7 @@ func (c *userController) GetParams(ctx context.Context, req *system.UserGetParam
res.RoleAccess = append(res.RoleAccess, v.Id)
}
} else {
res.RoleAccess, err = service.SysUser().GetAdminRoleIds(ctx, userId)
res.RoleAccess, err = service.SysUser().GetAdminRoleIds(ctx, userId, true)
if err != nil {
return
}

View File

@ -20,6 +20,7 @@ type SysRoleDao struct {
// SysRoleColumns defines and stores column names for table sys_role.
type SysRoleColumns struct {
Id string //
Pid string //
Status string // 状态;0:禁用;1:正常
ListOrder string // 排序
Name string // 角色名称
@ -33,6 +34,7 @@ type SysRoleColumns struct {
// sysRoleColumns holds the columns for table sys_role.
var sysRoleColumns = SysRoleColumns{
Id: "id",
Pid: "pid",
Status: "status",
ListOrder: "list_order",
Name: "name",

View File

@ -49,7 +49,7 @@ func (s *sSysRole) GetRoleListSearch(ctx context.Context, req *system.RoleListRe
//获取当前用户所属角色ids
if !service.SysUser().IsSupperAdmin(ctx, userId) {
var roleIds []uint
roleIds, err = service.SysUser().GetAdminRoleIds(ctx, userId)
roleIds, err = service.SysUser().GetAdminRoleIds(ctx, userId, true)
liberr.ErrIsNil(ctx, err)
if len(roleIds) == 0 {
return
@ -57,19 +57,15 @@ func (s *sSysRole) GetRoleListSearch(ctx context.Context, req *system.RoleListRe
model = model.Where("a."+dao.SysRole.Columns().Id+" in(?) OR a.created_by = ?", roleIds, userId)
}
model = model.As("a")
res.Total, err = model.Count()
liberr.ErrIsNil(ctx, err, "获取角色数据失败")
if req.PageNum == 0 {
req.PageNum = 1
if service.ToolsGenTable().IsMysql() {
model = model.LeftJoin("casbin_rule", "b", "b.v1 = a.id ")
model = model.LeftJoin("sys_user", "u", "CONCAT('u_',u.id) = b.v0 ")
} else {
model = model.LeftJoin("casbin_rule", "b", "b.v1 = cast(a.id AS VARCHAR) ")
model = model.LeftJoin("sys_user", "u", "CONCAT('u_',u.id) = b.v0")
}
res.CurrentPage = req.PageNum
if req.PageSize == 0 {
req.PageSize = consts.PageSize
}
model = model.LeftJoin("casbin_rule", "b", "b.v1 = cast(a.id AS char) ")
model = model.LeftJoin("sys_user", "u", "CONCAT('u_',u.id) = cast(b.v0 AS char)")
model = model.Group("a.id")
err = model.Page(res.CurrentPage, req.PageSize).Order("id asc").Fields("a.*, count(u.id) user_cnt").Scan(&res.List)
err = model.Order("id asc").Fields("a.*, count(u.id) user_cnt").Scan(&res.List)
liberr.ErrIsNil(ctx, err, "获取数据失败")
})
return
@ -110,8 +106,10 @@ func (s *sSysRole) AddRoleRule(ctx context.Context, ruleIds []uint, roleId int64
for k, v := range ruleIdsStr {
rules[k] = []string{gconv.String(roleId), v, "All"}
}
if len(rules) > 0 {
_, err = enforcer.AddPolicies(rules)
liberr.ErrIsNil(ctx, err)
}
})
return
}
@ -150,7 +148,7 @@ func (s *sSysRole) AddRole(ctx context.Context, req *system.RoleAddReq) (err err
func (s *sSysRole) Get(ctx context.Context, id uint) (res *entity.SysRole, err error) {
err = g.Try(ctx, func(ctx context.Context) {
//判断是否具有此角色的权限
if !s.hasManageAccess(ctx, id) {
if !s.hasManageAccess(ctx, id, true) {
liberr.ErrIsNil(ctx, errors.New("没有查看这个角色的权限"))
}
err = dao.SysRole.Ctx(ctx).WherePri(id).Scan(&res)
@ -173,7 +171,7 @@ func (s *sSysRole) GetFilteredNamedPolicy(ctx context.Context, id uint) (gpSlice
return
}
func (s *sSysRole) hasManageAccess(ctx context.Context, roleId uint) bool {
func (s *sSysRole) hasManageAccess(ctx context.Context, roleId uint, includeChildren ...bool) bool {
currentUserId := service.Context().GetUserId(ctx)
if !service.SysUser().IsSupperAdmin(ctx, currentUserId) {
var (
@ -193,7 +191,7 @@ func (s *sSysRole) hasManageAccess(ctx context.Context, roleId uint) bool {
return true
}
}
roleIds, err = service.SysUser().GetAdminRoleIds(ctx, service.Context().GetUserId(ctx))
roleIds, err = service.SysUser().GetAdminRoleIds(ctx, service.Context().GetUserId(ctx), includeChildren...)
if err != nil {
g.Log().Error(ctx, err)
return false
@ -216,10 +214,11 @@ func (s *sSysRole) EditRole(ctx context.Context, req *system.RoleEditReq) (err e
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
err = g.Try(ctx, func(ctx context.Context) {
//判断是否具有修改此角色的权限
if !s.hasManageAccess(ctx, gconv.Uint(req.Id)) {
if !s.hasManageAccess(ctx, gconv.Uint(req.Id), true) {
liberr.ErrIsNil(ctx, errors.New("没有修改这个角色的权限"))
}
_, e := dao.SysRole.Ctx(ctx).TX(tx).WherePri(req.Id).Data(&do.SysRole{
Pid: req.Pid,
Status: req.Status,
ListOrder: req.ListOrder,
Name: req.Name,
@ -346,3 +345,27 @@ func (s *sSysRole) RoleDataScope(ctx context.Context, req *system.DataScopeReq)
})
return err
}
func (s *sSysRole) FindSonByParentId(roleList []*entity.SysRole, id uint) []*entity.SysRole {
children := make([]*entity.SysRole, 0, len(roleList))
for _, v := range roleList {
if v.Pid == id {
children = append(children, v)
fChildren := s.FindSonByParentId(roleList, v.Id)
children = append(children, fChildren...)
}
}
return children
}
func (s *sSysRole) FindSonIdsByParentId(roleList []*entity.SysRole, id uint) []uint {
children := make([]uint, 0, len(roleList))
for _, v := range roleList {
if v.Pid == id {
children = append(children, v.Id)
fChildren := s.FindSonIdsByParentId(roleList, v.Id)
children = append(children, fChildren...)
}
}
return children
}

View File

@ -205,7 +205,7 @@ func (s *sSysUser) GetAdminRole(ctx context.Context, userId uint64, allRoleList
}
// GetAdminRoleIds 获取用户角色ids
func (s *sSysUser) GetAdminRoleIds(ctx context.Context, userId uint64) (roleIds []uint, err error) {
func (s *sSysUser) GetAdminRoleIds(ctx context.Context, userId uint64, includeChildren ...bool) (roleIds []uint, err error) {
enforcer, e := commonService.CasbinEnforcer(ctx)
if e != nil {
err = e
@ -220,6 +220,21 @@ func (s *sSysUser) GetAdminRoleIds(ctx context.Context, userId uint64) (roleIds
roleIds[k] = gconv.Uint(v[1])
}
}
if len(includeChildren) > 0 && includeChildren[0] {
//获取子级
var allRoles []*entity.SysRole
allRoles, err = service.SysRole().GetRoleList(ctx)
if err != nil {
return
}
childrenIds := make([]uint, 0, 100)
for _, roleId := range roleIds {
childrenIds = append(childrenIds, service.SysRole().FindSonIdsByParentId(allRoles, roleId)...)
}
//合并去重
roleIds = append(roleIds, childrenIds...)
}
roleIds = libUtils.SliceUnique(roleIds)
return
}
@ -484,13 +499,13 @@ func (s *sSysUser) getSearchDeptIds(ctx context.Context, deptId uint64) (deptIds
}
// 过滤用户可操作的角色
func (s *sSysUser) filterRoleIds(ctx context.Context, roleIds []uint, userId uint64) (newRoleIds []uint, err error) {
func (s *sSysUser) filterRoleIds(ctx context.Context, roleIds []uint, userId uint64, includeChildren ...bool) (newRoleIds []uint, err error) {
err = g.Try(ctx, func(ctx context.Context) {
var (
accessRoleList []uint
roleList []*entity.SysRole
)
accessRoleList, err = service.SysUser().GetAdminRoleIds(ctx, userId)
accessRoleList, err = service.SysUser().GetAdminRoleIds(ctx, userId, includeChildren...)
liberr.ErrIsNil(ctx, err)
roleList, err = service.SysRole().GetRoleList(ctx)
liberr.ErrIsNil(ctx, err)

View File

@ -13,6 +13,7 @@ import (
type SysRole struct {
g.Meta `orm:"table:sys_role, do:true"`
Id interface{} //
Pid interface{} //
Status interface{} // 状态;0:禁用;1:正常
ListOrder interface{} // 排序
Name interface{} // 角色名称

View File

@ -11,6 +11,7 @@ import (
// SysRole is the golang structure for table sys_role.
type SysRole struct {
Id uint `json:"id" description:""`
Pid uint `json:"pid" description:""`
Status uint `json:"status" description:"状态;0:禁用;1:正常"`
ListOrder uint `json:"listOrder" description:"排序"`
Name string `json:"name" description:"角色名称"`

View File

@ -26,6 +26,8 @@ type (
RoleDeptTreeSelect(ctx context.Context, roleId int64) (res *system.RoleDeptTreeSelectRes, err error)
GetRoleDepts(ctx context.Context, roleId int64) ([]int64, error)
RoleDataScope(ctx context.Context, req *system.DataScopeReq) error
FindSonByParentId(roleList []*entity.SysRole, id uint) []*entity.SysRole
FindSonIdsByParentId(roleList []*entity.SysRole, id uint) []uint
}
)

View File

@ -30,7 +30,7 @@ type (
UpdateLoginInfo(ctx context.Context, id uint64, ip string,openId ...string) (err error)
GetAdminRules(ctx context.Context, userId uint64) (menuList []*model.UserMenus, permissions []string, err error)
GetAdminRole(ctx context.Context, userId uint64, allRoleList []*entity.SysRole) (roles []*entity.SysRole, err error)
GetAdminRoleIds(ctx context.Context, userId uint64) (roleIds []uint, err error)
GetAdminRoleIds(ctx context.Context, userId uint64,includeChildren ...bool) (roleIds []uint, err error)
GetAllMenus(ctx context.Context) (menus []*model.UserMenus, err error)
GetAdminMenusIdsByRoleIds(ctx context.Context, roleIds []uint) (menuIds *garray.Array, err error)
GetAdminMenusByRoleIds(ctx context.Context, roleIds []uint) (menus []*model.UserMenus, err error)

View File

@ -9,5 +9,5 @@ package consts
const (
Logo = `CiAgIF9fX19fX19fX19fXyAgICAgICAgICAgX18gCiAgLyBfX19fLyBfX19fL19fXyBfX19fX18vIC9fCiAvIC8gX18vIC9fICAvIF9fIGAvIF9fXy8gX18vCi8gL18vIC8gX18vIC8gL18vIChfXyAgKSAvXyAgClxfX19fL18vICAgIFxfXyxfL19fX18vXF9fLyAg`
Version = "3.2.14"
Version = "3.2.15"
)

View File

@ -194,3 +194,17 @@ func GetFilesPath(ctx context.Context, fileUrl string) (path string, err error)
}
return
}
// SliceUnique 数字元素去重
func SliceUnique[T comparable](slice []T) []T {
encountered := map[T]bool{}
result := []T{}
for _, v := range slice {
if !encountered[v] {
encountered[v] = true
result = append(result, v)
}
}
return result
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -322,7 +322,7 @@ func(c *{{$structName}}Controller) Linked{{$.table.ClassName}}DataSearch(ctx con
{{if ne $.table.ModuleName "system"}}
{{$serviceVal = "systemService"}}
{{end}}
if !{{$serviceVal}}.SysUser().AccessRule(ctx, {{$serviceVal}}.Context().GetUserId(ctx), "{{.apiVersion}}/{{.table.PackageName}}/{{$businessName}}/list") {
if !{{$serviceVal}}.SysUser().AccessRule(ctx, {{$serviceVal}}.Context().GetUserId(ctx), "{{.apiVersion}}/{{.modulePath}}/{{.table.BusinessName | CaseCamelLower}}/list") {
err = errors.New("没有访问权限")
return
}