diff --git a/server/api/v1/system/sys_user.go b/server/api/v1/system/sys_user.go index 45d008acd0a613ed02fe35a8050a1c9bf33b8cee..f627aa5c739f19d3d330c3e0cb425dc2b195de87 100644 --- a/server/api/v1/system/sys_user.go +++ b/server/api/v1/system/sys_user.go @@ -9,6 +9,7 @@ import ( systemReq "gin-vue-admin/model/system/request" systemRes "gin-vue-admin/model/system/response" "gin-vue-admin/utils" + "strconv" "time" "github.com/dgrijalva/jwt-go" @@ -119,7 +120,13 @@ func (b *BaseApi) Register(c *gin.Context) { response.FailWithMessage(err.Error(), c) return } - user := &system.SysUser{Username: r.Username, NickName: r.NickName, Password: r.Password, HeaderImg: r.HeaderImg, AuthorityId: r.AuthorityId} + var authorities []system.SysAuthority + for _, v := range r.AuthorityIds { + authorities = append(authorities, system.SysAuthority{ + AuthorityId: v, + }) + } + user := &system.SysUser{Username: r.Username, NickName: r.NickName, Password: r.Password, HeaderImg: r.HeaderImg, AuthorityId: r.AuthorityId, Authorities: authorities} err, userReturn := userService.Register(*user) if err != nil { global.GVA_LOG.Error("注册失败!", zap.Any("err", err)) @@ -181,7 +188,7 @@ func (b *BaseApi) GetUserList(c *gin.Context) { } // @Tags SysUser -// @Summary 设置用户权限 +// @Summary 更改用户权限 // @Security ApiKeyAuth // @accept application/json // @Produce application/json @@ -195,7 +202,39 @@ func (b *BaseApi) SetUserAuthority(c *gin.Context) { response.FailWithMessage(UserVerifyErr.Error(), c) return } - if err := userService.SetUserAuthority(sua.UUID, sua.AuthorityId); err != nil { + userID := utils.GetUserID(c) + uuid := utils.GetUserUuid(c) + if err := userService.SetUserAuthority(userID, uuid, sua.AuthorityId); err != nil { + global.GVA_LOG.Error("修改失败!", zap.Any("err", err)) + response.FailWithMessage(err.Error(), c) + } else { + claims := utils.GetUserInfo(c) + j := &middleware.JWT{SigningKey: []byte(global.GVA_CONFIG.JWT.SigningKey)} // 唯一签名 + claims.AuthorityId = sua.AuthorityId + if token, err := j.CreateToken(*claims); err != nil { + global.GVA_LOG.Error("修改失败!", zap.Any("err", err)) + response.FailWithMessage(err.Error(), c) + } else { + c.Header("new-token", token) + c.Header("new-expires-at", strconv.FormatInt(claims.ExpiresAt, 10)) + response.OkWithMessage("修改成功", c) + } + + } +} + +// @Tags SysUser +// @Summary 设置用户权限 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body systemReq.SetUserAuthorities true "用户UUID, 角色ID" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"修改成功"}" +// @Router /user/setUserAuthorities [post] +func (b *BaseApi) SetUserAuthorities(c *gin.Context) { + var sua systemReq.SetUserAuthorities + _ = c.ShouldBindJSON(&sua) + if err := userService.SetUserAuthorities(sua.ID, sua.AuthorityIds); err != nil { global.GVA_LOG.Error("修改失败!", zap.Any("err", err)) response.FailWithMessage("修改失败", c) } else { @@ -253,3 +292,20 @@ func (b *BaseApi) SetUserInfo(c *gin.Context) { response.OkWithDetailed(gin.H{"userInfo": ReqUser}, "设置成功", c) } } + +// @Tags SysUser +// @Summary 获取用户信息 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /user/getUserInfo [get] +func (b *BaseApi) GetUserInfo(c *gin.Context) { + uuid := utils.GetUserUuid(c) + if err, ReqUser := userService.GetUserInfo(uuid); err != nil { + global.GVA_LOG.Error("获取失败!", zap.Any("err", err)) + response.FailWithMessage("获取失败", c) + } else { + response.OkWithDetailed(gin.H{"userInfo": ReqUser}, "获取成功", c) + } +} diff --git a/server/model/system/request/sys_casbin.go b/server/model/system/request/sys_casbin.go index 40ac21cd74ba3cb6d0aa27bfb8120be969746b5c..d0031dcff4c5d08eab48fa8eb7e429193ea9470b 100644 --- a/server/model/system/request/sys_casbin.go +++ b/server/model/system/request/sys_casbin.go @@ -13,5 +13,14 @@ type CasbinInReceive struct { } func DefaultCasbin() []CasbinInfo { - return []CasbinInfo{{Path: "/menu/getMenu", Method: "POST"}, {Path: "/jwt/jsonInBlacklist", Method: "POST"}} + return []CasbinInfo{ + {Path: "/menu/getMenu", Method: "POST"}, + {Path: "/jwt/jsonInBlacklist", Method: "POST"}, + {Path: "/base/login", Method: "POST"}, + {Path: "/user/register", Method: "POST"}, + {Path: "/user/changePassword", Method: "POST"}, + {Path: "/user/setUserAuthority", Method: "POST"}, + {Path: "/user/setUserInfo", Method: "PUT"}, + {Path: "/user/getUserInfo", Method: "GET"}, + } } diff --git a/server/model/system/request/sys_user.go b/server/model/system/request/sys_user.go index f2b147ed804f8ee0308cbc0245cb9d61ed7ffe73..84ab1ef47cec8b6429aea173961d0e646cfbb4e3 100644 --- a/server/model/system/request/sys_user.go +++ b/server/model/system/request/sys_user.go @@ -1,14 +1,13 @@ package request -import uuid "github.com/satori/go.uuid" - // User register structure type Register struct { - Username string `json:"userName"` - Password string `json:"passWord"` - NickName string `json:"nickName" gorm:"default:'QMPlusUser'"` - HeaderImg string `json:"headerImg" gorm:"default:'http://www.henrongyi.top/avatar/lufu.jpg'"` - AuthorityId string `json:"authorityId" gorm:"default:888"` + Username string `json:"userName"` + Password string `json:"passWord"` + NickName string `json:"nickName" gorm:"default:'QMPlusUser'"` + HeaderImg string `json:"headerImg" gorm:"default:'http://www.henrongyi.top/avatar/lufu.jpg'"` + AuthorityId string `json:"authorityId" gorm:"default:888"` + AuthorityIds []string `json:"authorityIds"` } // User login structure @@ -28,6 +27,11 @@ type ChangePasswordStruct struct { // Modify user's auth structure type SetUserAuth struct { - UUID uuid.UUID `json:"uuid"` // 用户UUID - AuthorityId string `json:"authorityId"` // 角色ID + AuthorityId string `json:"authorityId"` // 角色ID +} + +// Modify user's auth structure +type SetUserAuthorities struct { + ID uint + AuthorityIds []string `json:"authorityIds"` // 角色ID } diff --git a/server/model/system/sys_user.go b/server/model/system/sys_user.go index aeb2acd6e106c8c29097d51a017b9d76782d14a7..1fccf157497b4ad060f9d9892675c95507e2a0ae 100644 --- a/server/model/system/sys_user.go +++ b/server/model/system/sys_user.go @@ -7,14 +7,15 @@ import ( type SysUser struct { global.GVA_MODEL - UUID uuid.UUID `json:"uuid" gorm:"comment:用户UUID"` // 用户UUID - Username string `json:"userName" gorm:"comment:用户登录名"` // 用户登录名 - Password string `json:"-" gorm:"comment:用户登录密码"` // 用户登录密码 - NickName string `json:"nickName" gorm:"default:系统用户;comment:用户昵称"` // 用户昵称 - HeaderImg string `json:"headerImg" gorm:"default:http://qmplusimg.henrongyi.top/head.png;comment:用户头像"` // 用户头像 - Authority SysAuthority `json:"authority" gorm:"foreignKey:AuthorityId;references:AuthorityId;comment:用户角色"` - AuthorityId string `json:"authorityId" gorm:"default:888;comment:用户角色ID"` // 用户角色ID - SideMode string `json:"sideMode" gorm:"default:dark;comment:用户角色ID"` // 用户侧边主题 - ActiveColor string `json:"activeColor" gorm:"default:#1890ff;comment:用户角色ID"` // 活跃颜色 - BaseColor string `json:"baseColor" gorm:"default:#fff;comment:用户角色ID"` // 基础颜色 + UUID uuid.UUID `json:"uuid" gorm:"comment:用户UUID"` // 用户UUID + Username string `json:"userName" gorm:"comment:用户登录名"` // 用户登录名 + Password string `json:"-" gorm:"comment:用户登录密码"` // 用户登录密码 + NickName string `json:"nickName" gorm:"default:系统用户;comment:用户昵称"` // 用户昵称 + HeaderImg string `json:"headerImg" gorm:"default:http://qmplusimg.henrongyi.top/head.png;comment:用户头像"` // 用户头像 + Authority SysAuthority `json:"authority" gorm:"foreignKey:AuthorityId;references:AuthorityId;comment:用户角色"` + AuthorityId string `json:"authorityId" gorm:"default:888;comment:用户角色ID"` // 用户角色ID + SideMode string `json:"sideMode" gorm:"default:dark;comment:用户角色ID"` // 用户侧边主题 + ActiveColor string `json:"activeColor" gorm:"default:#1890ff;comment:用户角色ID"` // 活跃颜色 + BaseColor string `json:"baseColor" gorm:"default:#fff;comment:用户角色ID"` // 基础颜色 + Authorities []SysAuthority `json:"authorities" gorm:"many2many:sys_user_authority;"` } diff --git a/server/model/system/sys_user_authority.go b/server/model/system/sys_user_authority.go new file mode 100644 index 0000000000000000000000000000000000000000..ba37605a7922130747c2c3ae3335fd149aa176c9 --- /dev/null +++ b/server/model/system/sys_user_authority.go @@ -0,0 +1,10 @@ +package system + +type SysUseAuthority struct { + SysUserId uint `gorm:"column:sys_user_id"` + SysAuthorityAuthorityId string `gorm:"column:sys_authority_authority_id"` +} + +func (s *SysUseAuthority) TableName() string { + return "sys_user_authority" +} diff --git a/server/router/system/sys_user.go b/server/router/system/sys_user.go index 24aef1436c8790d87363133a96e67e84262625af..25455d6bce950535c788e00d5951afa10e2c23c1 100644 --- a/server/router/system/sys_user.go +++ b/server/router/system/sys_user.go @@ -13,11 +13,13 @@ func (s *UserRouter) InitUserRouter(Router *gin.RouterGroup) { userRouter := Router.Group("user").Use(middleware.OperationRecord()) var baseApi = v1.ApiGroupApp.SystemApiGroup.BaseApi { - userRouter.POST("register", baseApi.Register) // 用户注册账号 - userRouter.POST("changePassword", baseApi.ChangePassword) // 用户修改密码 - userRouter.POST("getUserList", baseApi.GetUserList) // 分页获取用户列表 - userRouter.POST("setUserAuthority", baseApi.SetUserAuthority) // 设置用户权限 - userRouter.DELETE("deleteUser", baseApi.DeleteUser) // 删除用户 - userRouter.PUT("setUserInfo", baseApi.SetUserInfo) // 设置用户信息 + userRouter.POST("register", baseApi.Register) // 用户注册账号 + userRouter.POST("changePassword", baseApi.ChangePassword) // 用户修改密码 + userRouter.POST("getUserList", baseApi.GetUserList) // 分页获取用户列表 + userRouter.POST("setUserAuthority", baseApi.SetUserAuthority) // 设置用户权限 + userRouter.DELETE("deleteUser", baseApi.DeleteUser) // 删除用户 + userRouter.PUT("setUserInfo", baseApi.SetUserInfo) // 设置用户信息 + userRouter.POST("setUserAuthorities", baseApi.SetUserAuthorities) // 设置用户权限组 + userRouter.GET("getUserInfo", baseApi.GetUserInfo) // 获取自身信息 } } diff --git a/server/service/system/sys_authority.go b/server/service/system/sys_authority.go index 33138e1ae612209fcef7849d5e9cc50b3588e85a..8881ffcc0feaec7e9a1d7fbd825b6be2f964cf62 100644 --- a/server/service/system/sys_authority.go +++ b/server/service/system/sys_authority.go @@ -92,6 +92,7 @@ func (authorityService *AuthorityService) DeleteAuthority(auth *system.SysAuthor } else { err = db.Error } + err = global.GVA_DB.Delete(&[]system.SysUseAuthority{}, "sys_authority_authority_id = ?", auth.AuthorityId).Error CasbinServiceApp.ClearCasbin(0, auth.AuthorityId) return err } diff --git a/server/service/system/sys_initdb.go b/server/service/system/sys_initdb.go index 265f0075fbfb321f598a740ccc45a0353694c42c..91ac5ba5f9548b3f44b63a4f481b6a4e44f9cdb3 100644 --- a/server/service/system/sys_initdb.go +++ b/server/service/system/sys_initdb.go @@ -152,7 +152,9 @@ func (initDBService *InitDBService) InitDB(conf request.InitDB) error { source.Dictionary, source.DictionaryDetail, source.File, - source.BaseMenu) + source.BaseMenu, + source.UserAuthority, + ) if err != nil { global.GVA_DB = nil return err diff --git a/server/service/system/sys_user.go b/server/service/system/sys_user.go index e3b44992c1d88e1fefad3d794ed444577edf6b75..894c3e56752ab2a35a4d31c110e522c25a364697 100644 --- a/server/service/system/sys_user.go +++ b/server/service/system/sys_user.go @@ -40,7 +40,7 @@ func (userService *UserService) Register(u system.SysUser) (err error, userInter func (userService *UserService) Login(u *system.SysUser) (err error, userInter *system.SysUser) { var user system.SysUser u.Password = utils.MD5V([]byte(u.Password)) - err = global.GVA_DB.Where("username = ? AND password = ?", u.Username, u.Password).Preload("Authority").First(&user).Error + err = global.GVA_DB.Where("username = ? AND password = ?", u.Username, u.Password).Preload("Authorities").Preload("Authority").First(&user).Error return err, &user } @@ -69,7 +69,7 @@ func (userService *UserService) GetUserInfoList(info request.PageInfo) (err erro db := global.GVA_DB.Model(&system.SysUser{}) var userList []system.SysUser err = db.Count(&total).Error - err = db.Limit(limit).Offset(offset).Preload("Authority").Find(&userList).Error + err = db.Limit(limit).Offset(offset).Preload("Authorities").Preload("Authority").Find(&userList).Error return err, userList, total } @@ -79,11 +79,42 @@ func (userService *UserService) GetUserInfoList(info request.PageInfo) (err erro //@param: uuid uuid.UUID, authorityId string //@return: err error -func (userService *UserService) SetUserAuthority(uuid uuid.UUID, authorityId string) (err error) { +func (userService *UserService) SetUserAuthority(id uint, uuid uuid.UUID, authorityId string) (err error) { + assignErr := global.GVA_DB.Where("sys_user_id = ? AND sys_authority_authority_id = ?", id, authorityId).First(&system.SysUseAuthority{}).Error + if errors.Is(assignErr, gorm.ErrRecordNotFound) { + return errors.New("该用户无此角色") + } err = global.GVA_DB.Where("uuid = ?", uuid).First(&system.SysUser{}).Update("authority_id", authorityId).Error return err } +//@author: [piexlmax](https://github.com/piexlmax) +//@function: SetUserAuthorities +//@description: 设置一个用户的权限 +//@param: id uint, authorityIds []string +//@return: err error + +func (userService *UserService) SetUserAuthorities(id uint, authorityIds []string) (err error) { + return global.GVA_DB.Transaction(func(tx *gorm.DB) error { + TxErr := tx.Delete(&[]system.SysUseAuthority{}, "sys_user_id = ?", id).Error + if TxErr != nil { + return TxErr + } + useAuthority := []system.SysUseAuthority{} + for _, v := range authorityIds { + useAuthority = append(useAuthority, system.SysUseAuthority{ + id, v, + }) + } + TxErr = tx.Create(&useAuthority).Error + if TxErr != nil { + return TxErr + } + // 返回 nil 提交事务 + return nil + }) +} + //@author: [piexlmax](https://github.com/piexlmax) //@function: DeleteUser //@description: 删除用户 @@ -93,6 +124,7 @@ func (userService *UserService) SetUserAuthority(uuid uuid.UUID, authorityId str func (userService *UserService) DeleteUser(id float64) (err error) { var user system.SysUser err = global.GVA_DB.Where("id = ?", id).Delete(&user).Error + err = global.GVA_DB.Delete(&[]system.SysUseAuthority{}, "sys_user_id = ?", id).Error return err } @@ -107,6 +139,18 @@ func (userService *UserService) SetUserInfo(reqUser system.SysUser) (err error, return err, reqUser } +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetUserInfo +//@description: 获取用户信息 +//@param: uuid uuid.UUID +//@return: err error, user system.SysUser + +func (userService *UserService) GetUserInfo(uuid uuid.UUID) (err error, user system.SysUser) { + var reqUser system.SysUser + err = global.GVA_DB.Preload("Authorities").Preload("Authority").First(&reqUser, "uuid = ?", uuid).Error + return err, reqUser +} + //@author: [SliverHorn](https://github.com/SliverHorn) //@function: FindUserById //@description: 通过id获取用户信息 diff --git a/server/source/api.go b/server/source/api.go index e97e952c896aa57606c9ee1665ce16c86df2a1cc..d46d76684198059ed83c785379e615b02799495b 100644 --- a/server/source/api.go +++ b/server/source/api.go @@ -14,8 +14,8 @@ var Api = new(api) type api struct{} var apis = []system.SysApi{ - {global.GVA_MODEL{ID: 1, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/base/login", "用户登录", "base", "POST"}, - {global.GVA_MODEL{ID: 2, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/user/register", "用户注册", "user", "POST"}, + {global.GVA_MODEL{ID: 1, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/base/login", "用户登录(必选)", "base", "POST"}, + {global.GVA_MODEL{ID: 2, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/user/register", "用户注册(必选)", "user", "POST"}, {global.GVA_MODEL{ID: 3, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/api/createApi", "创建api", "api", "POST"}, {global.GVA_MODEL{ID: 4, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/api/getApiList", "获取api列表", "api", "POST"}, {global.GVA_MODEL{ID: 5, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/api/getApiById", "获取api详细信息", "api", "POST"}, @@ -25,7 +25,7 @@ var apis = []system.SysApi{ {global.GVA_MODEL{ID: 9, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/authority/createAuthority", "创建角色", "authority", "POST"}, {global.GVA_MODEL{ID: 10, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/authority/deleteAuthority", "删除角色", "authority", "POST"}, {global.GVA_MODEL{ID: 11, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/authority/getAuthorityList", "获取角色列表", "authority", "POST"}, - {global.GVA_MODEL{ID: 12, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/menu/getMenu", "获取菜单树", "menu", "POST"}, + {global.GVA_MODEL{ID: 12, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/menu/getMenu", "获取菜单树(必选)", "menu", "POST"}, {global.GVA_MODEL{ID: 13, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/menu/getMenuList", "分页获取基础menu列表", "menu", "POST"}, {global.GVA_MODEL{ID: 14, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/menu/addBaseMenu", "新增菜单", "menu", "POST"}, {global.GVA_MODEL{ID: 15, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/menu/getBaseMenuTree", "获取用户动态路由", "menu", "POST"}, @@ -34,15 +34,15 @@ var apis = []system.SysApi{ {global.GVA_MODEL{ID: 18, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/menu/deleteBaseMenu", "删除菜单", "menu", "POST"}, {global.GVA_MODEL{ID: 19, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/menu/updateBaseMenu", "更新菜单", "menu", "POST"}, {global.GVA_MODEL{ID: 20, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/menu/getBaseMenuById", "根据id获取菜单", "menu", "POST"}, - {global.GVA_MODEL{ID: 21, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/user/changePassword", "修改密码", "user", "POST"}, + {global.GVA_MODEL{ID: 21, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/user/changePassword", "修改密码(建议选择)", "user", "POST"}, {global.GVA_MODEL{ID: 23, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/user/getUserList", "获取用户列表", "user", "POST"}, - {global.GVA_MODEL{ID: 24, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/user/setUserAuthority", "修改用户角色", "user", "POST"}, + {global.GVA_MODEL{ID: 24, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/user/setUserAuthority", "修改用户角色(必选)", "user", "POST"}, {global.GVA_MODEL{ID: 25, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/fileUploadAndDownload/upload", "文件上传示例", "fileUploadAndDownload", "POST"}, {global.GVA_MODEL{ID: 26, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/fileUploadAndDownload/getFileList", "获取上传文件列表", "fileUploadAndDownload", "POST"}, {global.GVA_MODEL{ID: 27, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/casbin/updateCasbin", "更改角色api权限", "casbin", "POST"}, {global.GVA_MODEL{ID: 28, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/casbin/getPolicyPathByAuthorityId", "获取权限列表", "casbin", "POST"}, {global.GVA_MODEL{ID: 29, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/fileUploadAndDownload/deleteFile", "删除文件", "fileUploadAndDownload", "POST"}, - {global.GVA_MODEL{ID: 30, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/jwt/jsonInBlacklist", "jwt加入黑名单(退出)", "jwt", "POST"}, + {global.GVA_MODEL{ID: 30, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/jwt/jsonInBlacklist", "jwt加入黑名单(退出,必选)", "jwt", "POST"}, {global.GVA_MODEL{ID: 31, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/authority/setDataAuthority", "设置角色资源权限", "authority", "POST"}, {global.GVA_MODEL{ID: 32, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/system/getSystemConfig", "获取配置文件内容", "system", "POST"}, {global.GVA_MODEL{ID: 33, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/system/setSystemConfig", "设置配置文件内容", "system", "POST"}, @@ -77,7 +77,7 @@ var apis = []system.SysApi{ {global.GVA_MODEL{ID: 62, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/simpleUploader/upload", "插件版分片上传", "simpleUploader", "POST"}, {global.GVA_MODEL{ID: 63, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/simpleUploader/checkFileMd5", "文件完整度验证", "simpleUploader", "GET"}, {global.GVA_MODEL{ID: 64, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/simpleUploader/mergeFileMd5", "上传完成合并文件", "simpleUploader", "GET"}, - {global.GVA_MODEL{ID: 65, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/user/setUserInfo", "设置用户信息", "user", "PUT"}, + {global.GVA_MODEL{ID: 65, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/user/setUserInfo", "设置用户信息(必选)", "user", "PUT"}, {global.GVA_MODEL{ID: 66, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/system/getServerInfo", "获取服务器信息", "system", "POST"}, {global.GVA_MODEL{ID: 67, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/email/emailTest", "发送测试邮件", "email", "POST"}, {global.GVA_MODEL{ID: 80, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/autoCode/preview", "预览自动化代码", "autoCode", "POST"}, @@ -90,6 +90,8 @@ var apis = []system.SysApi{ {global.GVA_MODEL{ID: 87, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/autoCode/rollback", "回滚自动生成代码", "autoCode", "POST"}, {global.GVA_MODEL{ID: 88, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/autoCode/getMeta", "获取meta信息", "autoCode", "POST"}, {global.GVA_MODEL{ID: 89, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/autoCode/delSysHistory", "删除回滚记录", "autoCode", "POST"}, + {global.GVA_MODEL{ID: 90, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/user/setUserAuthorities", "设置权限组", "user", "POST"}, + {global.GVA_MODEL{ID: 91, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/user/getUserInfo", "获取自身信息(必选)", "user", "GET"}, } //@author: [SliverHorn](https://github.com/SliverHorn) diff --git a/server/source/casbin.go b/server/source/casbin.go index 59036c24424de2c93f289201e748c087b60472d1..909bb2d2fe1a252b2160e546f11b975c9704476b 100644 --- a/server/source/casbin.go +++ b/server/source/casbin.go @@ -90,6 +90,8 @@ var carbines = []gormadapter.CasbinRule{ {PType: "p", V0: "888", V1: "/autoCode/rollback", V2: "POST"}, {PType: "p", V0: "888", V1: "/autoCode/getMeta", V2: "POST"}, {PType: "p", V0: "888", V1: "/autoCode/delSysHistory", V2: "POST"}, + {PType: "p", V0: "888", V1: "/user/setUserAuthorities", V2: "POST"}, + {PType: "p", V0: "888", V1: "/user/getUserInfo", V2: "GET"}, {PType: "p", V0: "8881", V1: "/base/login", V2: "POST"}, {PType: "p", V0: "8881", V1: "/user/register", V2: "POST"}, {PType: "p", V0: "8881", V1: "/api/createApi", V2: "POST"}, @@ -127,6 +129,7 @@ var carbines = []gormadapter.CasbinRule{ {PType: "p", V0: "8881", V1: "/customer/customer", V2: "DELETE"}, {PType: "p", V0: "8881", V1: "/customer/customer", V2: "GET"}, {PType: "p", V0: "8881", V1: "/customer/customerList", V2: "GET"}, + {PType: "p", V0: "8881", V1: "/user/getUserInfo", V2: "GET"}, {PType: "p", V0: "9528", V1: "/base/login", V2: "POST"}, {PType: "p", V0: "9528", V1: "/user/register", V2: "POST"}, {PType: "p", V0: "9528", V1: "/api/createApi", V2: "POST"}, @@ -165,6 +168,7 @@ var carbines = []gormadapter.CasbinRule{ {PType: "p", V0: "9528", V1: "/customer/customer", V2: "GET"}, {PType: "p", V0: "9528", V1: "/customer/customerList", V2: "GET"}, {PType: "p", V0: "9528", V1: "/autoCode/createTemp", V2: "POST"}, + {PType: "p", V0: "9528", V1: "/user/getUserInfo", V2: "GET"}, } //@author: [SliverHorn](https://github.com/SliverHorn) diff --git a/server/source/user_authority.go.go b/server/source/user_authority.go.go new file mode 100644 index 0000000000000000000000000000000000000000..197675c9a22bd54186f7041991ad27804b863fc7 --- /dev/null +++ b/server/source/user_authority.go.go @@ -0,0 +1,34 @@ +package source + +import ( + "gin-vue-admin/global" + "gin-vue-admin/model/system" + "github.com/gookit/color" + "gorm.io/gorm" +) + +var UserAuthority = new(userAuthority) + +type userAuthority struct{} + +var userAuthorityModel = []system.SysUseAuthority{ + {1, "888"}, + {1, "8881"}, + {1, "9528"}, + {2, "888"}, +} + +//@description: user_authority 数据初始化 +func (a *userAuthority) Init() error { + return global.GVA_DB.Model(&system.SysUseAuthority{}).Transaction(func(tx *gorm.DB) error { + if tx.Where("sys_user_id IN (1, 2)").Find(&[]AuthorityMenus{}).RowsAffected == 4 { + color.Danger.Println("\n[Mysql] --> sys_user_authority 表的初始数据已存在!") + return nil + } + if err := tx.Create(&userAuthorityModel).Error; err != nil { // 遇到错误时回滚事务 + return err + } + color.Info.Println("\n[Mysql] --> sys_user_authority 表初始数据成功!") + return nil + }) +} diff --git a/server/utils/clamis.go b/server/utils/clamis.go index 1238331bdeb49d9e4341e6744a0c16d8649385f1..71deb93d74a8e48f662a3a39c099193fdef654f1 100644 --- a/server/utils/clamis.go +++ b/server/utils/clamis.go @@ -4,6 +4,7 @@ import ( "gin-vue-admin/global" systemReq "gin-vue-admin/model/system/request" "github.com/gin-gonic/gin" + uuid "github.com/satori/go.uuid" ) // 从Gin的Context中获取从jwt解析出来的用户ID @@ -18,13 +19,13 @@ func GetUserID(c *gin.Context) uint { } // 从Gin的Context中获取从jwt解析出来的用户UUID -func GetUserUuid(c *gin.Context) string { +func GetUserUuid(c *gin.Context) uuid.UUID { if claims, exists := c.Get("claims"); !exists { global.GVA_LOG.Error("从Gin的Context中获取从jwt解析出来的用户UUID失败, 请检查路由是否使用jwt中间件!") - return "" + return uuid.UUID{} } else { waitUse := claims.(*systemReq.CustomClaims) - return waitUse.UUID.String() + return waitUse.UUID } } @@ -38,3 +39,14 @@ func GetUserAuthorityId(c *gin.Context) string { return waitUse.AuthorityId } } + +// 从Gin的Context中获取从jwt解析出来的用户角色id +func GetUserInfo(c *gin.Context) *systemReq.CustomClaims { + if claims, exists := c.Get("claims"); !exists { + global.GVA_LOG.Error("从Gin的Context中获取从jwt解析出来的用户UUID失败, 请检查路由是否使用jwt中间件!") + return nil + } else { + waitUse := claims.(*systemReq.CustomClaims) + return waitUse + } +} diff --git a/server/utils/verify.go b/server/utils/verify.go index 9e5796f7fdb0dc45fdd723697a47dddabfb8257e..2725d473635a685be4776df3620ec36150ac9eb9 100644 --- a/server/utils/verify.go +++ b/server/utils/verify.go @@ -14,5 +14,5 @@ var ( AuthorityIdVerify = Rules{"AuthorityId": {NotEmpty()}} OldAuthorityVerify = Rules{"OldAuthorityId": {NotEmpty()}} ChangePasswordVerify = Rules{"Username": {NotEmpty()}, "Password": {NotEmpty()}, "NewPassword": {NotEmpty()}} - SetUserAuthorityVerify = Rules{"UUID": {NotEmpty()}, "AuthorityId": {NotEmpty()}} + SetUserAuthorityVerify = Rules{"AuthorityId": {NotEmpty()}} ) diff --git a/web/src/api/user.js b/web/src/api/user.js index a833888c2089af282fb63cba2d6ba7bf207eb840..32ee55c1299f9b7b34b4ea1e5a579377615e4462 100644 --- a/web/src/api/user.js +++ b/web/src/api/user.js @@ -111,3 +111,33 @@ export const setUserInfo = (data) => { data: data }) } + +// @Tags User +// @Summary 设置用户权限 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body api.setUserAuthorities true "设置用户权限" +// @Success 200 {string} json "{"success":true,"data":{},"msg":"修改成功"}" +// @Router /user/setUserAuthorities [post] +export const setUserAuthorities = (data) => { + return service({ + url: '/user/setUserAuthorities', + method: 'post', + data: data + }) +} + +// @Tags User +// @Summary 获取用户信息 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /user/getUserInfo [get] +export const getUserInfo = () => { + return service({ + url: '/user/getUserInfo', + method: 'get' + }) +} diff --git a/web/src/permission.js b/web/src/permission.js index eef9e36425ed6b142f2a8fe4d97261bdea715875..676240a8000d995fc46055e61770291ee8cc6bf0 100644 --- a/web/src/permission.js +++ b/web/src/permission.js @@ -23,6 +23,7 @@ router.beforeEach(async(to, from, next) => { if (!asyncRouterFlag && store.getters['router/asyncRouters'].length === 0) { asyncRouterFlag++ await store.dispatch('router/SetAsyncRouter') + await store.dispatch('user/GetUserInfo') const asyncRouters = store.getters['router/asyncRouters'] router.addRoutes(asyncRouters) next({ ...to, replace: true }) diff --git a/web/src/store/module/user.js b/web/src/store/module/user.js index 82ee944bf02b5373925320b035052688545f1acb..0e7908f95526e6be30b7ead8a0c2cbb8360fd210 100644 --- a/web/src/store/module/user.js +++ b/web/src/store/module/user.js @@ -1,4 +1,4 @@ -import { login } from '@/api/user' +import { login, getUserInfo } from '@/api/user' import { jsonInBlacklist } from '@/api/jwt' import router from '@/router/index' import { setUserInfo } from '@/api/user' @@ -56,6 +56,13 @@ export const user = { } }, actions: { + async GetUserInfo({ commit }) { + const res = await getUserInfo() + if (res.code === 0) { + commit('setUserInfo', res.data.userInfo) + } + return res + }, async LoginIn({ commit, dispatch, rootGetters, getters }, loginInfo) { const res = await login(loginInfo) if (res.code === 0) { diff --git a/web/src/view/layout/index.vue b/web/src/view/layout/index.vue index ae2a965df3fbd520ae670a7f9a9b10ca85db8ccf..7bb7d08ba1128a72c2f1b471dcb344a70d9316b6 100644 --- a/web/src/view/layout/index.vue +++ b/web/src/view/layout/index.vue @@ -45,11 +45,17 @@ - - 更多信息 - + + 当前角色:{{ userInfo.authority.authorityName }} + 个人信息 登 出 @@ -90,6 +96,7 @@ import BottomInfo from '@/view/layout/bottomInfo/bottomInfo' import { mapGetters, mapActions } from 'vuex' import CustomPic from '@/components/customPic' import Setting from './setting' +import { setUserAuthority } from '@/api/user' export default { name: 'Layout', components: { @@ -186,7 +193,15 @@ export default { } }, methods: { - ...mapActions('user', ['LoginOut']), + ...mapActions('user', ['LoginOut', 'GetUserInfo']), + async changeUserAuth(id) { + const res = await setUserAuthority({ + authorityId: id + }) + if (res.code === 0) { + window.location.reload() + } + }, reload() { this.reloadFlag = false this.$nextTick(() => { diff --git a/web/src/view/superAdmin/authority/authority.vue b/web/src/view/superAdmin/authority/authority.vue index a04cedc4b64156ba621b962f30433707ec35806c..8497af11a5c6629ea604d1729ae901ac54aaae6f 100644 --- a/web/src/view/superAdmin/authority/authority.vue +++ b/web/src/view/superAdmin/authority/authority.vue @@ -43,6 +43,7 @@ + 注:右上角头像下拉可切换角色 diff --git a/web/src/view/superAdmin/user/user.vue b/web/src/view/superAdmin/user/user.vue index 169f23428ac1d95d366faff23bdb198e78bb4426..7ecdc7177914ce45cde1fc88f6ad459976fe87d8 100644 --- a/web/src/view/superAdmin/user/user.vue +++ b/web/src/view/superAdmin/user/user.vue @@ -17,12 +17,14 @@ @@ -39,6 +41,7 @@ + 注:右上角头像下拉可切换角色 @@ -91,7 +95,7 @@ const path = process.env.VUE_APP_BASE_API import { getUserList, - setUserAuthority, + setUserAuthorities, register, deleteUser } from '@/api/user' @@ -115,7 +119,8 @@ export default { password: '', nickName: '', headerImg: '', - authorityId: '' + authorityId: '', + authorityIds: [] }, rules: { username: [ @@ -139,11 +144,20 @@ export default { ...mapGetters('user', ['token']) }, async created() { - this.getTableData() + await this.getTableData() + this.setAuthorityIds() const res = await getAuthorityList({ page: 1, pageSize: 999 }) this.setOptions(res.data.list) }, methods: { + setAuthorityIds() { + this.tableData && this.tableData.forEach((user) => { + const authorityIds = user.authorities && user.authorities.map(i => { + return i.authorityId + }) + this.$set(user, 'authorityIds', authorityIds) + }) + }, openHeaderChange() { this.$refs.chooseImg.open() }, @@ -174,11 +188,14 @@ export default { async deleteUser(row) { const res = await deleteUser({ id: row.ID }) if (res.code === 0) { - this.getTableData() + this.$message.success('删除成功') + await this.getTableData() + this.setAuthorityIds() row.visible = false } }, async enterAddUserDialog() { + this.userInfo.authorityId = this.userInfo.authorityIds[0] this.$refs.userForm.validate(async valid => { if (valid) { const res = await register(this.userInfo) @@ -186,6 +203,7 @@ export default { this.$message({ type: 'success', message: '创建成功' }) } await this.getTableData() + this.setAuthorityIds() this.closeAddUserDialog() } }) @@ -194,20 +212,22 @@ export default { this.$refs.userForm.resetFields() this.addUserDialog = false }, - handleAvatarSuccess(res) { - this.userInfo.headerImg = res.data.file.url - }, addUser() { this.addUserDialog = true }, - async changeAuthority(row) { - const res = await setUserAuthority({ - uuid: row.uuid, - authorityId: row.authority.authorityId - }) - if (res.code === 0) { - this.$message({ type: 'success', message: '角色设置成功' }) + async changeAuthority(row, flag) { + if (flag) { + return } + this.$nextTick(async() => { + const res = await setUserAuthorities({ + ID: row.ID, + authorityIds: row.authorityIds + }) + if (res.code === 0) { + this.$message({ type: 'success', message: '角色设置成功' }) + } + }) } } }