github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/rbac/rbac.go (about) 1 package rbac 2 3 import ( 4 "errors" 5 6 "gorm.io/gorm" 7 ) 8 9 var ( 10 ErrRoleNotFound = errors.New("role not found") 11 ErrPermNotFound = errors.New("permission not found") 12 ErrDeleteAssignedPerm = errors.New("cannot delete assigned permission") 13 ) 14 15 // UserRole represents the relationship between users and roles 16 type UserRole struct { 17 ID uint 18 UserID uint 19 RoleID uint 20 } 21 22 // TableName sets the table name 23 func (u UserRole) TableName() string { return tablePrefix + "user_roles" } 24 25 // Role represents the database model of roles 26 type Role struct { 27 ID uint 28 Name string 29 } 30 31 // TableName sets the table name 32 func (r Role) TableName() string { return tablePrefix + "roles" } 33 34 // RolePerm stores the relationship between roles and permissions 35 type RolePerm struct { 36 ID uint 37 RoleID uint 38 PermID uint 39 } 40 41 // TableName sets the table name 42 func (r RolePerm) TableName() string { return tablePrefix + "role_perms" } 43 44 // Perm represents the database model of permissions 45 type Perm struct { 46 ID uint 47 Name string 48 } 49 50 // TableName sets the table name 51 func (p Perm) TableName() string { return tablePrefix + "perms" } 52 53 // Rbac helps deal with permissions 54 type Rbac struct { 55 DB *gorm.DB 56 } 57 58 // Options has the options for initiating the package. 59 type Options struct { 60 DB *gorm.DB 61 TablesPrefix string 62 } 63 64 var ( 65 tablePrefix string 66 rbac *Rbac 67 ) 68 69 // New initiates authority. 70 func New(opts Options) *Rbac { 71 tablePrefix = opts.TablesPrefix 72 rbac = &Rbac{DB: opts.DB} 73 migrateTables(opts.DB) 74 return rbac 75 } 76 77 // Instance returns the initiated instance. 78 func Instance() *Rbac { return rbac } 79 80 // NewRole stores a role in the database it accepts the role name. 81 func (a *Rbac) NewRole(roleName string) error { 82 var dbRole Role 83 r := a.DB.Where("name=?", roleName).First(&dbRole) 84 if r.Error != nil && errors.Is(r.Error, gorm.ErrRecordNotFound) { 85 return a.DB.Create(&Role{Name: roleName}).Error 86 } 87 88 return r.Error 89 } 90 91 // NewPerm stores a permission in the database it accepts the permission name. 92 func (a *Rbac) NewPerm(permName string) error { 93 perm := Perm{} 94 r := a.DB.Where("name=?", permName).First(&perm) 95 if r.Error != nil && errors.Is(r.Error, gorm.ErrRecordNotFound) { 96 return a.DB.Create(&Perm{Name: permName}).Error 97 } 98 99 return r.Error 100 } 101 102 // AssignPerms assigns a group of permissions to a given role 103 // it accepts in the first parameter the role name, it returns an error if there is not matching record 104 // of the role name in the database. 105 // the second parameter is a slice of strings which represents a group of permissions to be assigned to the role 106 // if any of these permissions doesn't have a matching record in the database the operations stops, changes reverted 107 // and error is returned 108 // in case of success nothing is returned 109 func (a *Rbac) AssignPerms(roleName string, permNames ...string) error { 110 var role Role 111 if r := a.DB.Where("name=?", roleName).First(&role); r.Error != nil { 112 if errors.Is(r.Error, gorm.ErrRecordNotFound) { 113 return ErrRoleNotFound 114 } 115 return r.Error 116 } 117 118 var perms []Perm 119 for _, permName := range permNames { 120 var perm Perm 121 if r := a.DB.Where("name=?", permName).First(&perm); r.Error != nil { 122 if errors.Is(r.Error, gorm.ErrRecordNotFound) { 123 return ErrPermNotFound 124 } 125 return r.Error 126 } 127 128 perms = append(perms, perm) 129 } 130 131 // insert data into RolePermissions table 132 for _, perm := range perms { 133 // ignore any assigned permission 134 var rolePerm RolePerm 135 if r := a.DB.Where("role_id=?", role.ID).Where("perm_id =?", perm.ID).First(&rolePerm); r.Error != nil { // assign the record 136 if cRes := a.DB.Create(&RolePerm{RoleID: role.ID, PermID: perm.ID}); cRes.Error != nil { 137 return cRes.Error 138 } 139 } 140 } 141 142 return nil 143 } 144 145 // AssignRole assigns a given role to a user 146 // the first parameter is the user id, the second parameter is the role name 147 // if the role name doesn't have a matching record in the data base an error is returned 148 // if the user have already a role assigned to him an error is returned 149 func (a *Rbac) AssignRole(userID uint, roleName string) error { 150 // make sure the role exist 151 var role Role 152 if r := a.DB.Where("name=?", roleName).First(&role); r.Error != nil { 153 if errors.Is(r.Error, gorm.ErrRecordNotFound) { 154 return ErrRoleNotFound 155 } 156 return r.Error 157 } 158 159 // check if the role is already assigned 160 userRole := UserRole{} 161 if r := a.DB.Where("user_id=?", userID).Where("role_id=?", role.ID).First(&userRole); r.Error == nil { 162 return nil 163 } 164 165 // assign the role 166 a.DB.Create(&UserRole{UserID: userID, RoleID: role.ID}) 167 168 return nil 169 } 170 171 // CheckRole checks if a role is assigned to a user it accepts the user id as the first parameter 172 // the role as the second parameter 173 // it returns an error if the role is not present in database. 174 func (a *Rbac) CheckRole(userID uint, roleName string) (bool, error) { 175 // find the role 176 var role Role 177 if r := a.DB.Where("name=?", roleName).First(&role); r.Error != nil { 178 if errors.Is(r.Error, gorm.ErrRecordNotFound) { 179 return false, ErrRoleNotFound 180 } 181 return false, r.Error 182 } 183 184 // check if the role is assigned 185 userRole := UserRole{} 186 if r := a.DB.Where("user_id=?", userID).Where("role_id=?", role.ID).First(&userRole); r.Error != nil { 187 if errors.Is(r.Error, gorm.ErrRecordNotFound) { 188 return false, nil 189 } 190 return false, r.Error 191 } 192 193 return true, nil 194 } 195 196 // CheckPerm checks if a permission is assigned to the role that's assigned to the user. 197 // it accepts the user id as the first parameter 198 // the permission as the second parameter 199 // it returns an error if the permission is not present in the database 200 func (a *Rbac) CheckPerm(userID uint, permName string) (bool, error) { 201 var userRoles []UserRole 202 if r := a.DB.Where("user_id=?", userID).Find(&userRoles); r.Error != nil { 203 if errors.Is(r.Error, gorm.ErrRecordNotFound) { 204 return false, nil 205 } 206 return false, r.Error 207 } 208 209 // prepare an array of role ids 210 var roleIDs []uint 211 for _, r := range userRoles { 212 roleIDs = append(roleIDs, r.RoleID) 213 } 214 215 // find the permission 216 var perm Perm 217 if r := a.DB.Where("name=?", permName).First(&perm); r.Error != nil { 218 if errors.Is(r.Error, gorm.ErrRecordNotFound) { 219 return false, ErrPermNotFound 220 } 221 return false, r.Error 222 } 223 224 // find the role permission 225 var rolePerm RolePerm 226 r := a.DB.Where("role_id IN (?)", roleIDs).Where("perm_id=?", perm.ID).First(&rolePerm) 227 return r.Error == nil, nil 228 } 229 230 // CheckRolePerm checks if a role has the permission assigned 231 // it accepts the role as the first parameter 232 // it accepts the permission as the second parameter 233 // it returns an error if the role is not present in database 234 // it returns an error if the permission is not present in database 235 func (a *Rbac) CheckRolePerm(roleName string, permName string) (bool, error) { 236 // find the role 237 var role Role 238 if r := a.DB.Where("name=?", roleName).First(&role); r.Error != nil { 239 if errors.Is(r.Error, gorm.ErrRecordNotFound) { 240 return false, errors.New("role not found") 241 } 242 return false, r.Error 243 } 244 245 // find the permission 246 var perm Perm 247 if r := a.DB.Where("name=?", permName).First(&perm); r.Error != nil { 248 if errors.Is(r.Error, gorm.ErrRecordNotFound) { 249 return false, errors.New("permission not found") 250 } 251 return false, r.Error 252 } 253 254 // find the rolePerm 255 var rolePerm RolePerm 256 if r := a.DB.Where("role_id=?", role.ID).Where("perm_id=?", perm.ID).First(&rolePerm); r.Error != nil { 257 if errors.Is(r.Error, gorm.ErrRecordNotFound) { 258 return false, nil 259 } 260 return false, r.Error 261 } 262 263 return true, nil 264 } 265 266 // RevokeRole revokes a user's role 267 // it returns a error in case of any 268 func (a *Rbac) RevokeRole(userID uint, roleName string) error { 269 // find the role 270 var role Role 271 if r := a.DB.Where("name=?", roleName).First(&role); r.Error != nil { 272 if errors.Is(r.Error, gorm.ErrRecordNotFound) { 273 return ErrRoleNotFound 274 } 275 return r.Error 276 } 277 278 // revoke the role 279 return a.DB.Where("user_id=?", userID).Where("role_id=?", role.ID).Delete(UserRole{}).Error 280 } 281 282 // RevokePerm revokes a permission from the user's assigned role 283 // it returns an error in case of any 284 func (a *Rbac) RevokePerm(userID uint, permName string) error { 285 // revoke the permission from all roles of the user 286 // find the user roles 287 var userRoles []UserRole 288 if r := a.DB.Where("user_id=?", userID).Find(&userRoles); r.Error != nil { 289 if errors.Is(r.Error, gorm.ErrRecordNotFound) { 290 return nil 291 } 292 return r.Error 293 } 294 295 // find the permission 296 var perm Perm 297 if r := a.DB.Where("name=?", permName).First(&perm); r.Error != nil { 298 if errors.Is(r.Error, gorm.ErrRecordNotFound) { 299 return ErrPermNotFound 300 } 301 return r.Error 302 } 303 304 for _, r := range userRoles { // revoke the permission 305 a.DB.Where("role_id=?", r.RoleID).Where("perm_id=?", perm.ID).Delete(RolePerm{}) 306 } 307 308 return nil 309 } 310 311 // RevokeRolePerm revokes a permission from a given role 312 // it returns an error in case of any 313 func (a *Rbac) RevokeRolePerm(roleName string, permName string) error { 314 // find the role 315 var role Role 316 if r := a.DB.Where("name=?", roleName).First(&role); r.Error != nil { 317 if errors.Is(r.Error, gorm.ErrRecordNotFound) { 318 return ErrRoleNotFound 319 } 320 return r.Error 321 } 322 323 // find the permission 324 var perm Perm 325 if r := a.DB.Where("name=?", permName).First(&perm); r.Error != nil { 326 if errors.Is(r.Error, gorm.ErrRecordNotFound) { 327 return ErrPermNotFound 328 } 329 return r.Error 330 } 331 332 // revoke the permission 333 return a.DB.Where("role_id=?", role.ID).Where("perm_id=?", perm.ID).Delete(RolePerm{}).Error 334 } 335 336 // GetRoles returns all stored roles 337 func (a *Rbac) GetRoles() ([]string, error) { 338 var result []string 339 var roles []Role 340 a.DB.Find(&roles) 341 342 for _, role := range roles { 343 result = append(result, role.Name) 344 } 345 346 return result, nil 347 } 348 349 // GetUserRoles returns all user assigned roles 350 func (a *Rbac) GetUserRoles(userID uint) ([]string, error) { 351 var result []string 352 var userRoles []UserRole 353 a.DB.Where("user_id=?", userID).Find(&userRoles) 354 355 for _, r := range userRoles { 356 var role Role 357 // for every user role get the role name 358 if r := a.DB.Where("id=?", r.RoleID).Find(&role); r.Error == nil { 359 result = append(result, role.Name) 360 } 361 } 362 363 return result, nil 364 } 365 366 // GetPerms returns all stored permissions 367 func (a *Rbac) GetPerms() ([]string, error) { 368 var result []string 369 var perms []Perm 370 a.DB.Find(&perms) 371 372 for _, perm := range perms { 373 result = append(result, perm.Name) 374 } 375 376 return result, nil 377 } 378 379 // DeleteRole deletes a given role 380 // if the role is assigned to a user it returns an error 381 func (a *Rbac) DeleteRole(roleName string) error { 382 // find the role 383 var role Role 384 if r := a.DB.Where("name=?", roleName).First(&role); r.Error != nil { 385 if errors.Is(r.Error, gorm.ErrRecordNotFound) { 386 return ErrRoleNotFound 387 } 388 return r.Error 389 } 390 391 // check if the role is assigned to a user 392 var userRole UserRole 393 if r := a.DB.Where("role_id=?", role.ID).First(&userRole); r.Error == nil { 394 return ErrDeleteAssignedPerm 395 } 396 397 // revoke the assignment of permissions before deleting the role 398 a.DB.Where("role_id=?", role.ID).Delete(RolePerm{}) 399 // delete the role 400 a.DB.Where("name=?", roleName).Delete(Role{}) 401 402 return nil 403 } 404 405 // DeletePerm deletes a given permission if the permission is assigned to a role it returns an error. 406 func (a *Rbac) DeletePerm(permName string) error { 407 // find the permission 408 var perm Perm 409 if r := a.DB.Where("name=?", permName).First(&perm); r.Error != nil { 410 if errors.Is(r.Error, gorm.ErrRecordNotFound) { 411 return ErrPermNotFound 412 } 413 return r.Error 414 } 415 416 // check if the permission is assigned to a role 417 var rolePerm RolePerm 418 if r := a.DB.Where("perm_id=?", perm.ID).First(&rolePerm); r.Error == nil { 419 return ErrDeleteAssignedPerm 420 } 421 422 // delete the permission 423 a.DB.Where("name=?", permName).Delete(Perm{}) 424 425 return nil 426 } 427 428 func migrateTables(db *gorm.DB) { 429 db.AutoMigrate(&Role{}) 430 db.AutoMigrate(&Perm{}) 431 db.AutoMigrate(&RolePerm{}) 432 db.AutoMigrate(&UserRole{}) 433 }