diff --git a/deploy/sql/init/user.sql b/deploy/sql/init/user.sql index 34f7370..d6a7214 100644 --- a/deploy/sql/init/user.sql +++ b/deploy/sql/init/user.sql @@ -198,4 +198,9 @@ REPLACE INTO `menu`(`app_code`,`code`,`name`,`parent_code`,`type`,`order`,`icon` REPLACE INTO `menu`(`app_code`,`code`,`name`,`parent_code`,`type`,`order`,`icon`,`path`,`child_path`,`is_show`,`created_by`) VALUES('user-busniss-center','application','应用','',1,4,'application','/application','',1,'admin'); -- init role -REPLACE INTO `role` (`code`,`name`,`created_by`) VALUES('admin','超级管理员','admin'); \ No newline at end of file +REPLACE INTO `role` (`code`,`name`,`created_by`) VALUES('super_admin','超级管理员','admin'); +REPLACE INTO `role` (`code`,`name`,`created_by`) VALUES('admin','管理员','admin'); +REPLACE INTO `role` (`code`,`name`,`created_by`) VALUES('develop','开发者','admin'); + + +REPLACE INTO `user_role` (`user_account`,`role_code`,`created_by`) VALUES('admin','super_admin','admin'); \ No newline at end of file diff --git a/internal/models/role/request.go b/internal/models/role/request.go index b60f8ff..c4297fd 100644 --- a/internal/models/role/request.go +++ b/internal/models/role/request.go @@ -41,11 +41,13 @@ type GetReq struct { } type AddUsersReq struct { - Ids []uint `json:"ids"` + RoleId uint `json:"role_id"` + Ids []uint `json:"ids"` } type RemoveUsersReq struct { - Ids []uint `json:"ids"` + Ids []uint `json:"ids"` + RoleId uint `json:"role_id"` } type OrgAuthorRoleType int @@ -61,7 +63,7 @@ type OrgAuthorBrief struct { } type AddOrgsReq struct { - Orgs OrgAuthorBrief `json:"orgs"` + Orgs []OrgAuthorBrief `json:"orgs"` } type RemoveOrgsReq struct { diff --git a/internal/repo/organization.go b/internal/repo/organization.go index 633c98b..9753481 100644 --- a/internal/repo/organization.go +++ b/internal/repo/organization.go @@ -47,6 +47,7 @@ type OrganizationRepo interface{ GetOrgs(ctx context.Context)(org []*Organization,err error) ExistOrgId(ctx context.Context,id uint)(bool,error) SetStatus(ctx context.Context,id uint,status OrganizationStatus)error + GetUserOrgsById(ctx context.Context,id uint)([]Organization,error) } type orginizationRepo struct{ @@ -95,4 +96,10 @@ func (o *orginizationRepo)ExistOrgId(ctx context.Context,id uint)(bool,error){ func (o *orginizationRepo)SetStatus(ctx context.Context,id uint,status OrganizationStatus)error{ return o.db.Model(Organization{}).Where("id = ?",id).Update("status",status).Error -} \ No newline at end of file +} + +func (o *orginizationRepo)GetUserOrgsById(ctx context.Context,id uint)(orgs []Organization,err error){ + err = o.db.Model(Organization{}).Select("organization.*").Joins("join user_organization on user_organization.org_id = organization.id").Where("user_organization.user_id = ?",id).Find(&orgs).Error + return +} + diff --git a/internal/repo/role.go b/internal/repo/role.go index 03e9015..21b8555 100644 --- a/internal/repo/role.go +++ b/internal/repo/role.go @@ -36,6 +36,15 @@ type RoleRepo interface{ Search(ctx context.Context,query Query)([]Role,error) GetById(ctx context.Context,id uint)(Role,error) DelById(ctx context.Context,id uint)error + + // 用户角色 + CreateUserRole(ctx context.Context,items []UserRole)error + GetUserRolesByAccount(ctx context.Context,account string)([]Role,error) + RemoveUserRole(ctx context.Context,items []UserRole)error + + // 组织角色 + GetOrgRolesByIDs(ctx context.Context,ids []uint)([]Role,error) + } type roleRepo struct{ @@ -97,4 +106,26 @@ func (r *roleRepo)GetById(ctx context.Context,id uint)(Role,error){ func (r *roleRepo)DelById(ctx context.Context,id uint)error{ return r.db.Where("id = ?",id).Delete(&Role{}).Error +} + +func (r *roleRepo)GetUserRolesByAccount(ctx context.Context,account string)([]Role,error){ + roles := make([]Role,0) + err := r.db.Model(Role{}).Joins("join user_role on user_role.role_code = role.code and user_role.user_account = ?",account).Find(&roles).Error + return roles,err +} + +func (r *roleRepo)GetOrgRolesByIDs(ctx context.Context,ids []uint)([]Role,error){ + roles := make([]Role,0) + err := r.db.Model(Role{}).Joins("join organization_role on organization_role.role_id = role.id and organization_role.org_id in ?",ids).Find(&roles).Error + return roles,err +} + +func (r *roleRepo)RemoveUserRole(ctx context.Context,items []UserRole)error{ + for _,item := range items{ + if err := r.db.Where("user_account = ? and role_code = ?",item.UserAccount,item.RoleCode).Delete(&UserRole{}).Error;err != nil{ + return err + } + } + + return nil } \ No newline at end of file diff --git a/internal/repo/user.go b/internal/repo/user.go index 0778c3e..222d451 100644 --- a/internal/repo/user.go +++ b/internal/repo/user.go @@ -45,6 +45,7 @@ type UserRepo interface { SearchCount(ctx context.Context, query *userModel.Query) (int64, error) ResetPwd(ctx context.Context, user User) error GetUserById(ctx context.Context, id uint) (user User, err error) + BatchGetUserByIDs(ctx context.Context, ids []uint) (users []User, err error) } type userRepoS struct { @@ -120,7 +121,12 @@ func (u *userRepoS) SearchCount(ctx context.Context, query *userModel.Query) (in return total, err } -func (u *userRepoS)GetUserById(ctx context.Context, id uint) (user User, err error){ +func (u *userRepoS) GetUserById(ctx context.Context, id uint) (user User, err error) { err = u.db.Where("id = ?", id).Take(&user).Error - return -} \ No newline at end of file + return +} + +func (u *userRepoS) BatchGetUserByIDs(ctx context.Context, ids []uint) (users []User, err error) { + err = u.db.Where("id in ?", ids).Find(&users).Error + return +} diff --git a/internal/repo/user_role.go b/internal/repo/user_role.go new file mode 100644 index 0000000..c866058 --- /dev/null +++ b/internal/repo/user_role.go @@ -0,0 +1,26 @@ +// Code generated by sql2gorm. DO NOT EDIT. +package repo + +import ( + "context" + "time" +) + +// 用户角色表 +type UserRole struct { + ID uint `gorm:"column:id;primary_key;AUTO_INCREMENT"` // id + UserAccount string `gorm:"column:user_account;NOT NULL"` // 用户账号 + RoleCode string `gorm:"column:role_code;NOT NULL"` // 名称 + CreatedBy string `gorm:"column:created_by"` // 创建人 + CreatedOn time.Time `gorm:"column:created_on;default:CURRENT_TIMESTAMP;NOT NULL"` // 记录创建时间 + ModifiedBy string `gorm:"column:modified_by"` // 修改人 + ModifiedOn time.Time `gorm:"column:modified_on;default:CURRENT_TIMESTAMP"` // 记录修改时间 +} + +func (m *UserRole) TableName() string { + return "user_role" +} + +func (r *roleRepo)CreateUserRole(ctx context.Context,items []UserRole)error{ + return r.db.Create(&items).Error +} \ No newline at end of file diff --git a/internal/service/role/interface.go b/internal/service/role/interface.go index 04db38a..7aaabb4 100644 --- a/internal/service/role/interface.go +++ b/internal/service/role/interface.go @@ -2,6 +2,7 @@ package role import ( roleModel "busniess-user-center/internal/models/role" + userModel "busniess-user-center/internal/models/user" "context" ) @@ -11,4 +12,13 @@ type RoleService interface { Delete(ctx context.Context, info *roleModel.DelReq) error Role(ctx context.Context, info *roleModel.GetReq) (roleModel.Role, error) Search(ctx context.Context, info *roleModel.Query) ([]roleModel.Role, error) + AddUsers(ctx context.Context, info *roleModel.AddUsersReq) error + RemoveUsers(ctx context.Context, info *roleModel.RemoveUsersReq) error + AddOrgs(ctx context.Context, info *roleModel.AddOrgsReq) error + RemoveOrgs(ctx context.Context, info *roleModel.RemoveOrgsReq) error + RoleUsers(ctx context.Context, info *roleModel.RoleUsersReq) ([]userModel.User, error) + RoleOrgs(ctx context.Context, info *roleModel.RoleOrgsReq) ([]roleModel.OrgRoleAuthor, error) + AuthorRoleMenu(ctx context.Context, info *roleModel.AuthorRoleMenuReq) error + RemoveRoleMenu(ctx context.Context, info *roleModel.RemoveReleMenuReq) error + RoleMenuAuthorList(ctx context.Context, info *roleModel.AddOrgsReq) ([]roleModel.RoleMenu, error) } diff --git a/internal/service/role/role.go b/internal/service/role/role.go index f1c515b..4b2a11a 100644 --- a/internal/service/role/role.go +++ b/internal/service/role/role.go @@ -3,7 +3,11 @@ package role import ( "busniess-user-center/config" roleModel "busniess-user-center/internal/models/role" + userModel "busniess-user-center/internal/models/user" "busniess-user-center/internal/repo" + "busniess-user-center/internal/service/user" + contextUtil "busniess-user-center/pkg/utils/context" + "busniess-user-center/pkg/utils/session" "context" "fmt" @@ -17,17 +21,25 @@ func init() { do.Provide(nil, NewRoleService) } +const ( + superAdmin = "super_admin" + admin = "admin" + develop = "develop" +) + type roleService struct { - logger *zap.SugaredLogger - roleRepo repo.RoleRepo - conf *config.AppConfig + logger *zap.SugaredLogger + roleRepo repo.RoleRepo + conf *config.AppConfig + userService user.UserService } func NewRoleService(i *do.Injector) (RoleService, error) { return &roleService{ - logger: do.MustInvoke[*zap.SugaredLogger](i), - roleRepo: do.MustInvoke[repo.RoleRepo](i), - conf: do.MustInvoke[*config.AppConfig](i), + logger: do.MustInvoke[*zap.SugaredLogger](i), + roleRepo: do.MustInvoke[repo.RoleRepo](i), + conf: do.MustInvoke[*config.AppConfig](i), + userService: do.MustInvoke[user.UserService](i), }, nil } @@ -94,3 +106,141 @@ func (o *roleService) Search(ctx context.Context, info *roleModel.Query) ([]role return roles, nil } + +func (o *roleService) AddUsers(ctx context.Context, info *roleModel.AddUsersReq) error { + role, err := o.roleRepo.GetById(ctx, info.RoleId) + if err != nil && err != gorm.ErrRecordNotFound { + return err + } + + if err == gorm.ErrRecordNotFound { + return fmt.Errorf("角色%d不存在", info.RoleId) + } + + // 判断权限 + session, err := contextUtil.GetSession(ctx) + if err != nil { + return err + } + + perssion, err := o.hasPerssion(ctx, session) + if err != nil { + return err + } + + if !perssion { + return fmt.Errorf("没有权限") + } + + // 获取用户 + users, err := o.userService.BatchGetUserByIDs(ctx, info.Ids) + if err != nil { + return err + } + + uRoles := make([]repo.UserRole, 0, len(users)) + for _, item := range users { + uRoles = append(uRoles, repo.UserRole{ + UserAccount: item.Account, + RoleCode: role.Code, + CreatedBy: session.Account, + }) + } + + if len(uRoles) > 0 { + err = o.roleRepo.CreateUserRole(ctx, uRoles) + } + + return err +} + +func (o *roleService) RemoveUsers(ctx context.Context, info *roleModel.RemoveUsersReq) error { + role, err := o.roleRepo.GetById(ctx, info.RoleId) + if err != nil && err != gorm.ErrRecordNotFound { + return err + } + + if err == gorm.ErrRecordNotFound { + return fmt.Errorf("角色%d不存在", info.RoleId) + } + + // 判断权限 + session, err := contextUtil.GetSession(ctx) + if err != nil { + return err + } + + perssion, err := o.hasPerssion(ctx, session) + if err != nil { + return err + } + + if !perssion { + return fmt.Errorf("没有权限") + } + + users, err := o.userService.BatchGetUserByIDs(ctx, info.Ids) + if err != nil { + return err + } + + uRoles := make([]repo.UserRole, 0, len(users)) + for _, item := range users { + uRoles = append(uRoles, repo.UserRole{ + UserAccount: item.Account, + RoleCode: role.Code, + CreatedBy: session.Account, + }) + } + + if len(uRoles) > 0 { + err = o.roleRepo.RemoveUserRole(ctx, uRoles) + } + + return nil +} + +func (u *roleService) AddOrgs(ctx context.Context, info *roleModel.AddOrgsReq) error { + return nil +} + +func (u *roleService) RemoveOrgs(ctx context.Context, info *roleModel.RemoveOrgsReq) error { + return nil +} + +func (u *roleService) RoleUsers(ctx context.Context, info *roleModel.RoleUsersReq) ([]userModel.User, error) { + return nil, nil +} + +func (u *roleService) RoleOrgs(ctx context.Context, info *roleModel.RoleOrgsReq) ([]roleModel.OrgRoleAuthor, error) { + return nil, nil +} + +func (u *roleService) AuthorRoleMenu(ctx context.Context, info *roleModel.AuthorRoleMenuReq) error { + return nil +} + +func (u *roleService) RemoveRoleMenu(ctx context.Context, info *roleModel.RemoveReleMenuReq) error { + return nil +} + +func (u *roleService) RoleMenuAuthorList(ctx context.Context, info *roleModel.AddOrgsReq) ([]roleModel.RoleMenu, error) { + return nil, nil +} + +func (u *roleService) hasPerssion(ctx context.Context, session *session.Session) (bool, error) { + user, err := u.userService.GetUser(ctx, &userModel.GetUserReq{Account: session.Account, AppCode: session.AppCode}) + if err != nil { + return false, err + } + + if len(user.Roles) > 0 { + for _, item := range user.Roles { + if item.Code == superAdmin || item.Code == develop || item.Code == admin { + return true, nil + } + } + } + + return false, nil +} diff --git a/internal/service/user/interface.go b/internal/service/user/interface.go index 777dac8..d02c934 100644 --- a/internal/service/user/interface.go +++ b/internal/service/user/interface.go @@ -17,4 +17,5 @@ type UserService interface { ResetPwd(ctx context.Context, req *userModel.ResetPwdReq) error GetUser(ctx context.Context, req *userModel.GetUserReq) (user userModel.User, err error) ExistUserByAccount(ctx context.Context, account string) (uint, error) + BatchGetUserByIDs(ctx context.Context,ids []uint)([]userModel.UserInfo,error) } diff --git a/internal/service/user/user.go b/internal/service/user/user.go index 8fb4ec3..5c843c2 100644 --- a/internal/service/user/user.go +++ b/internal/service/user/user.go @@ -2,6 +2,7 @@ package user import ( "busniess-user-center/config" + "busniess-user-center/internal/models/role" userModel "busniess-user-center/internal/models/user" "busniess-user-center/internal/repo" "busniess-user-center/pkg/redis" @@ -11,6 +12,7 @@ import ( "context" "fmt" + "github.com/jinzhu/copier" "github.com/samber/do" "go.uber.org/zap" "gorm.io/gorm" @@ -33,6 +35,8 @@ type userService struct { redis *redis.Redis conf *config.AppConfig tokenRefresher *token.TokenRefresher + roleRepo repo.RoleRepo + orgRepo repo.OrganizationRepo } func NewUserService(i *do.Injector) (UserService, error) { @@ -42,6 +46,8 @@ func NewUserService(i *do.Injector) (UserService, error) { redis: do.MustInvoke[*redis.Redis](i), conf: do.MustInvoke[*config.AppConfig](i), tokenRefresher: do.MustInvoke[*token.TokenRefresher](i), + roleRepo: do.MustInvoke[repo.RoleRepo](i), + orgRepo: do.MustInvoke[repo.OrganizationRepo](i), }, nil } @@ -260,7 +266,35 @@ func (u *userService) GetUser(ctx context.Context, req *userModel.GetUserReq) (u return } + // 获取组织 + orgIds := make([]uint, 0) + orgs, err := u.orgRepo.GetUserOrgsById(ctx, rUser.ID) + if err != nil { + return + } + + for _, item := range orgs { + orgIds = append(orgIds, item.ID) + } + + // 获取用户角色 + uRoles, err := u.roleRepo.GetUserRolesByAccount(ctx, rUser.Account) + if err != nil { + return + } + + // 获取组织角色 + oRoles, err := u.roleRepo.GetOrgRolesByIDs(ctx, orgIds) + if err != nil { + return + } + user = convertUser(rUser) + aRoles := removeRepeatRole(uRoles, oRoles) + + user.Roles = make([]role.Role, 0, len(aRoles)) + copier.Copy(&user.Roles, aRoles) + return } @@ -276,3 +310,14 @@ func (u *userService) ExistUserByAccount(ctx context.Context, account string) (u return user.ID, nil } + +func (u *userService) BatchGetUserByIDs(ctx context.Context, ids []uint) ([]userModel.UserInfo, error) { + list, err := u.repo.BatchGetUserByIDs(ctx, ids) + if err != nil { + return nil, err + } + + rList := make([]userModel.UserInfo, 0, len(list)) + copier.Copy(&rList, list) + return rList, nil +} diff --git a/internal/service/user/util.go b/internal/service/user/util.go index 5539c43..7dcfd94 100644 --- a/internal/service/user/util.go +++ b/internal/service/user/util.go @@ -5,6 +5,7 @@ import ( "busniess-user-center/internal/repo" "context" "fmt" + "sort" "time" "github.com/dgrijalva/jwt-go" @@ -12,14 +13,19 @@ import ( "github.com/golang-module/dongle" ) +const ( + userAppCode = "user-busniss-center" +) + func creteLoginTokenClaims(user *repo.User, expire int) jwt.MapClaims { now := time.Now() expiredAt := now.Unix() + int64(expire) userTokenClaims := jwt.MapClaims{ - "id": user.ID, - "account": user.Account, - "exp": expiredAt, - "_flag": now, + "id": user.ID, + "account": user.Account, + "app_code": userAppCode, + "exp": expiredAt, + "_flag": now, } return userTokenClaims @@ -69,7 +75,7 @@ func (u *userService) removeCookie(ctx context.Context) { } func convertUserList(users []repo.User) []userModel.User { - list := make([]userModel.User,0, len(users)) + list := make([]userModel.User, 0, len(users)) for _, item := range users { list = append(list, convertUser(item)) } @@ -89,3 +95,27 @@ func convertUser(user repo.User) userModel.User { }, } } + +func removeRepeatRole(sroles ...[]repo.Role) []repo.Role { + roles := make([]repo.Role, 0) + roleMap := make(map[uint]repo.Role, 0) + + for _, item := range sroles { + for _, role := range item { + if _, ok := roleMap[role.ID]; !ok { + roleMap[role.ID] = role + } + } + } + + for _, role := range roleMap { + roles = append(roles, role) + } + + sort.Slice(roles, func(i, j int) bool { + return roles[i].ID < roles[j].ID + }) + + return roles +} + diff --git a/pkg/middleware/jwt/jwt.go b/pkg/middleware/jwt/jwt.go index 61f9b83..8ef01e4 100644 --- a/pkg/middleware/jwt/jwt.go +++ b/pkg/middleware/jwt/jwt.go @@ -27,6 +27,7 @@ var ( JwtIdentityKey = "id" Account = "account" tokenName = "token" + AppCode = "app_code" whiteUrlList = map[string]bool{ "/api/user/login": true, @@ -64,6 +65,7 @@ func NewJwtAuthMiddleware(logger *zap.SugaredLogger, refresher *token.TokenRefre var ( id uint = 0 account = "" + appCode = "" ) claims := jwt.ExtractClaims(c) @@ -78,6 +80,11 @@ func NewJwtAuthMiddleware(logger *zap.SugaredLogger, refresher *token.TokenRefre id = cast.ToUint(idInterface) } + appCodeInterface, ok := claims[AppCode] + if ok { + appCode = appCodeInterface.(string) + } + // 从redis获取 _, err := refresher.GetUserToken(id) if err != nil { @@ -87,6 +94,7 @@ func NewJwtAuthMiddleware(logger *zap.SugaredLogger, refresher *token.TokenRefre return &session.Session{ ID: id, Account: account, + AppCode: appCode, } }, Authenticator: func(c *gin.Context) (interface{}, error) { diff --git a/pkg/utils/session/session.go b/pkg/utils/session/session.go index cb265f7..2af1764 100644 --- a/pkg/utils/session/session.go +++ b/pkg/utils/session/session.go @@ -3,4 +3,5 @@ package session type Session struct { ID uint `json:"id"` Account string `json:"account"` + AppCode string `json:"app_code` } diff --git a/server/role/role.go b/server/role/role.go index 454441d..870aaa0 100644 --- a/server/role/role.go +++ b/server/role/role.go @@ -36,6 +36,8 @@ func RegisterRoute(api *gin.RouterGroup) { api.DELETE("/delete", ginUtil.WrapNoRsp(server.DelRole)) api.GET("/get", ginUtil.Wrap(server.Role)) api.GET("/search", ginUtil.Wrap(server.Search)) + api.POST("/adduser", ginUtil.WrapNoRsp(server.AddUsers)) + api.DELETE("/removeuser", ginUtil.WrapNoRsp(server.RemoveUsers)) } func (u *RoleServer) Create(ctx context.Context, req *roleModel.CreateReq) (err error) { @@ -61,37 +63,37 @@ func (u *RoleServer) Search(ctx context.Context, info *roleModel.Query) ([]roleM } func (u *RoleServer) AddUsers(ctx context.Context, info *roleModel.AddUsersReq) error { - return nil + return u.roleService.AddUsers(ctx, info) } func (u *RoleServer) RemoveUsers(ctx context.Context, info *roleModel.RemoveUsersReq) error { - return nil + return u.roleService.RemoveUsers(ctx, info) } func (u *RoleServer) AddOrgs(ctx context.Context, info *roleModel.AddOrgsReq) error { - return nil + return u.roleService.AddOrgs(ctx, info) } func (u *RoleServer) RemoveOrgs(ctx context.Context, info *roleModel.RemoveOrgsReq) error { - return nil + return u.roleService.RemoveOrgs(ctx, info) } func (u *RoleServer) RoleUsers(ctx context.Context, info *roleModel.RoleUsersReq) ([]userModel.User, error) { - return nil, nil + return u.roleService.RoleUsers(ctx, info) } func (u *RoleServer) RoleOrgs(ctx context.Context, info *roleModel.RoleOrgsReq) ([]roleModel.OrgRoleAuthor, error) { - return nil, nil + return u.roleService.RoleOrgs(ctx, info) } func (u *RoleServer) AuthorRoleMenu(ctx context.Context, info *roleModel.AuthorRoleMenuReq) error { - return nil + return u.roleService.AuthorRoleMenu(ctx, info) } func (u *RoleServer) RemoveRoleMenu(ctx context.Context, info *roleModel.RemoveReleMenuReq) error { - return nil + return u.roleService.RemoveRoleMenu(ctx, info) } func (u *RoleServer) RoleMenuAuthorList(ctx context.Context, info *roleModel.AddOrgsReq) ([]roleModel.RoleMenu, error) { - return nil, nil + return u.roleService.RoleMenuAuthorList(ctx, info) }