Przeglądaj źródła

增加多角色功能和角色切换功能
调整前端获取用户信息方式

pixel 3 lat temu
rodzic
commit
2c714e288b

+ 59 - 3
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)
+	}
+}

+ 10 - 1
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"},
+	}
 }

+ 13 - 9
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
 }

+ 11 - 10
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;"`
 }

+ 10 - 0
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"
+}

+ 8 - 6
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)                // 获取自身信息
 	}
 }

+ 1 - 0
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
 }

+ 3 - 1
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

+ 47 - 3
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获取用户信息

+ 9 - 7
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)

+ 4 - 0
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)

+ 34 - 0
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
+	})
+}

+ 15 - 3
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
+	}
+}

+ 1 - 1
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()}}
 )

+ 30 - 0
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'
+  })
+}

+ 1 - 0
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 })

+ 8 - 1
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) {

+ 19 - 4
web/src/view/layout/index.vue

@@ -45,11 +45,17 @@
                       </span>
                       <el-dropdown-menu slot="dropdown" class="dropdown-group">
                         <el-dropdown-item>
-                          <span>
-                            更多信息
-                            <el-badge is-dot />
+                          <span style="font-weight: 600;">
+                            当前角色:{{ userInfo.authority.authorityName }}
                           </span>
                         </el-dropdown-item>
+                        <template v-if="userInfo.authorities">
+                          <el-dropdown-item v-for="item in userInfo.authorities.filter(i=>i.authorityId!==userInfo.authorityId)" :key="item.authorityId" @click.native="changeUserAuth(item.authorityId)">
+                            <span>
+                              切换为:{{ item.authorityName }}
+                            </span>
+                          </el-dropdown-item>
+                        </template>
                         <el-dropdown-item icon="el-icon-s-custom" @click.native="toPerson">个人信息</el-dropdown-item>
                         <el-dropdown-item icon="el-icon-table-lamp" @click.native="LoginOut">登 出</el-dropdown-item>
                       </el-dropdown-menu>
@@ -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(() => {

+ 1 - 0
web/src/view/superAdmin/authority/authority.vue

@@ -43,6 +43,7 @@
         </template>
       </el-table-column>
     </el-table>
+    <span style="color: red;font-size: 12px">注:右上角头像下拉可切换角色</span>
     <!-- 新增角色弹窗 -->
     <el-dialog :title="dialogTitle" :visible.sync="dialogFormVisible">
       <el-form ref="authorityForm" :model="form" :rules="rules">

+ 39 - 19
web/src/view/superAdmin/user/user.vue

@@ -17,12 +17,14 @@
       <el-table-column label="用户角色" min-width="150">
         <template slot-scope="scope">
           <el-cascader
-            v-model="scope.row.authority.authorityId"
+            v-model="scope.row.authorityIds"
             :options="authOptions"
             :show-all-levels="false"
-            :props="{ checkStrictly: true,label:'authorityName',value:'authorityId',disabled:'disabled',emitPath:false}"
+            :props="{ multiple:true,checkStrictly: true,label:'authorityName',value:'authorityId',disabled:'disabled',emitPath:false}"
             filterable
-            @change="changeAuthority(scope.row)"
+            :clearable="false"
+            @visible-change="(flag)=>{changeAuthority(scope.row,flag)}"
+            @remove-tag="()=>{changeAuthority(scope.row,false)}"
           />
         </template>
       </el-table-column>
@@ -39,6 +41,7 @@
         </template>
       </el-table-column>
     </el-table>
+    <span style="color: red;font-size: 12px">注:右上角头像下拉可切换角色</span>
     <el-pagination
       :current-page="page"
       :page-size="pageSize"
@@ -69,11 +72,12 @@
         </el-form-item>
         <el-form-item label="用户角色" label-width="80px" prop="authorityId">
           <el-cascader
-            v-model="userInfo.authorityId"
+            v-model="userInfo.authorityIds"
             :options="authOptions"
             :show-all-levels="false"
-            :props="{ checkStrictly: true,label:'authorityName',value:'authorityId',disabled:'disabled',emitPath:false}"
+            :props="{ multiple:true,checkStrictly: true,label:'authorityName',value:'authorityId',disabled:'disabled',emitPath:false}"
             filterable
+            :clearable="false"
           />
         </el-form-item>
       </el-form>
@@ -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: '角色设置成功' })
+        }
+      })
     }
   }
 }