go 实战 (类unix)鉴权系统核心

go 实战 (类unix)鉴权系统核心

截屏2023-09-07 14.14.45.png Linux上查看user组成,这里uid和gid是独立的,我们这里写的微核心就直接uid和gid绑定了,如果你想隔离user和group也可设立为和linux同款

截屏2023-09-07 14.55.04.png 还有一个容易被忽略的概念是执行者,例如上面这张截图,执行id这个命令的用户就是cho。 上代码。权限码仍然是4读,2写,1执行 再看这张截图,d代表类型为目录,r代表读(4),w代表可写(2),x代表可执行的(1),-代表没有权限(0),一共会有9位,每3位为一组(3位数字相加就为权限数字),每一组代表不同作用域,分别是(本用户,同组,其它),这里权限数字就为755,第一个cho为所属用户名,第二个cho为所属用户组

截屏2023-09-07 15.05.45.png

package permsys

import (
    "fmt"
)

type User struct {
    Uid  uint32
    Name string
}
type Group struct {
    Users map[uint32]*User
}
type Perm struct {
    OwnerId  uint32
    GroupId  uint32
    PermInfo [3]uint8
}

var groupmap = make(map[uint32]*Group)
var userlist = []User{}
var abandoned_user = make(map[uint32]struct{})
//获得执行权限码,先验证是否管理员组,由于这里uid和gid关联了,就没有单独的sudo(wheel)组了
func GetPerm(user *User, perm *Perm) uint8 {
    if isroot(user.Uid) { //it's root group,return all permission
        return 7
    }
    if user.Uid == perm.OwnerId {//用户本户返回第一组权限码
        return perm.PermInfo[0]
    } else if grp, ok := groupmap[perm.GroupId]; ok {
        for _, usr := range grp.Users {
            if usr.Uid == user.Uid {//同组用户,返回第二组权限码
                return perm.PermInfo[1]
            }
        }
    }
        //其它用户,返回第三组权限码
    return perm.PermInfo[2]
}
//对鉴权系统的操作就要涉及操纵者了(避免普通用户能对整套系统进行操作!),如果不是管理员组的用户将无法操作
func AddUser(usr *User, name string) {
    if !isroot(usr.Uid) {
        fmt.Printf("[error] Permission Denied Adduser %dn", usr.Uid)
        return
    }
    uid := uint32(len(userlist))
    userlist = append(userlist, User{uid, name})
    groupmap[uid] = &Group{map[uint32]*User{uid: &userlist[uid]}}
}
//验证用户是否为管理员组的
func isroot(uid uint32) bool {
    if uid == 0 {
        return true
    }
    for _, usr := range groupmap[0].Users {
        if usr.Uid == uid {
            return true
        }
    }
    return false
}
func isingroup(uid, gid uint32) bool {
    if ptr, ok := groupmap[gid]; ok {
        for _, usrptr := range ptr.Users {
            if usrptr.Uid == uid {
                return true
            }
        }
    }
    return false
}
//只有管理员有权限更改用户到指定组
func (s *User) AddUserToGroup(uid, gid uint32) error {
    var err error
    if _, ok := abandoned_user[uid]; ok || uid >= uint32(len(userlist)) {
        err = fmt.Errorf("user %d is not existed", uid)
        return err
    } else if !isroot(s.Uid) {
        err = fmt.Errorf("Permission Denied")
    } else {
        if usrptr, ok := groupmap[gid]; ok {
            if _, ok := usrptr.Users[uid]; !ok {
                usrptr.Users[uid] = &userlist[uid]
            } else {
                return fmt.Errorf("user already in group")
            }
        } else {
            err = fmt.Errorf("group don't existed")
        }
    }
    return err
}
func (s *User) GetPerm(perm *Perm) uint8 {
    return GetPerm(s, perm)
}
//将用户从组中剥离,同样需要管理员权限
func (s *User) RemoveUserFromGroup(uid, gid uint32) error {
    var err error
    if isroot(s.Uid) || s.Uid == gid {
        if _, ok := groupmap[gid]; ok {
            if _, ok = groupmap[gid].Users[uid]; ok {
                delete(groupmap[gid].Users, uid)
            } else {
                err = fmt.Errorf("user not in group")
            }
        } else {
            err = fmt.Errorf("group don't existed")
        }
    } else {
        err = fmt.Errorf("Permission Denied")
    }
    return err
}
//根据权限码生成权限实例
func CreatePerm(usr *User, mod string) (Perm, error) {
    perm := Perm{OwnerId: usr.Uid, GroupId: usr.Uid}
    if len(mod) != 3 {
        return perm, fmt.Errorf("mod is invalid")
    }
    for i := 0; i 7{
            return perm, fmt.Errorf("%d is not correct", perm.PermInfo[i])
        }
    }
    return perm, nil
}
//删除用户,需要管理员权限
func DelUser(usr *User, uid uint32) error {
    var err error
    if isroot(usr.Uid) && uid != 0 {
        if _, ok := abandoned_user[uid]; !ok && uid < uint32(len(userlist)) {
            abandoned_user[uid] = struct{}{}
        } else {
            err = fmt.Errorf("User is Invalid")
        }
    } else {
        err = fmt.Errorf("Permission Denied")
    }
    return err
}