go实用小技能(三)-使用二进制进行权限控制

今天分享的是使用二进制权限控制。

我们在go开发中经常会遇到使用二进制进行权限控制的情况,只不过go已经帮我们封装好了,不需要我们再人为进行管理。 比如在调用os.OpenFile()打开文件的时候

package main

import (
	"fmt"
	"io/ioutil"
	"os"
)

func main() {
	// 在这里我们打开了一个只读的文件
	onlyRead, _ := os.OpenFile("./hello.txt", os.O_RDONLY, os.ModePerm)
	defer onlyRead.Close()
	data, err := ioutil.ReadAll(onlyRead)
	if err != nil {
		fmt.Printf("Can't read to hello.txt :%v \n ", err)
	}
	fmt.Printf("hello.txt :%s \n", string(data))
	// 因为我们打开的是一个只读的文件
	// 在这里尝试写入文件,会抛出一个  panic: write ./hello.txt: bad file descriptor
	_, err = onlyRead.Write([]byte("This is a demo!!!"))
	if err != nil {
		fmt.Printf("Can't write to hello.txt :%v \n ", err)
	} else {
		fmt.Printf("Write to hello.txt  success ... \n ")
	}

	// 接下来我们打开一个可读可写的文件
	// 这里我们用到 | 或运算符
	readWrite, _ := os.OpenFile("./hello1.txt", os.O_CREATE|os.O_RDWR, os.ModePerm)
	data, err = ioutil.ReadAll(readWrite)
	if err != nil {
		fmt.Printf("Can't read to hello1.txt :%v \n ", err)
	}
	fmt.Printf("hello1.txt :%s \n", string(data))

	_, err = readWrite.Write([]byte("This is a demo!!!"))
	if err != nil {
		fmt.Printf("Can't write to hello1.txt :%v \n ", err)
	} else {
		fmt.Printf("Write to hello1.txt  success ... \n ")
	}
	// 下面是程序运行结果:
	// hello.txt :hello world!
	// 可以看到第一次打开的hello.txt在写入文件的时候报错了
	// Can't write to hello.txt :write ./hello.txt: bad file descriptor
	// hello1.txt :Hello1 world!This is a demo!!!This is a demo!!!
	// Write to hello1.txt  success ...
}

注意看我们第二次打开hello1.txt的时候, 我们使用了 | 这个或运算符

readWrite, _ := os.OpenFile("./hello1.txt", os.O_CREATE|os.O_RDWR, os.ModePerm)

下面我们通过示例介绍 | 位或 和 & 位与运算符

package main

import (
	"fmt"
)

const (
	// 游客
	TOURIST = 1 << iota
	// 会员 1
	MEMBER
	// 管理员
	// 管理拥有所有的权限
	MANAGER = TOURIST | MEMBER
)

func main() {
	fmt.Printf("TOURIST:%b, MEMBER:%b, MANAGER:%b \n", TOURIST, MEMBER, MANAGER)
	// 上面权限转成二进制:
	// TOURIST => 0001
	// MEMBER => 0010
	// MANAGER => 0011

	tourist(TOURIST, "用户1")
	// 输出:
	// flag:1 & needFlag:11 = 1
	// flag: 0001
	// needFlag: 0011
	// 与运算结果:0001
	// 用户:用户1 验证成功,可以访问 tourist ()
	
	
	
	tourist(MEMBER, "用户2")
	// 输出:
	// flag:10 & needFlag:11 = 10
	// flag:        0010
	// needFlag: 0011
	// 与运算结果:0010
	// 用户:用户2 验证成功,可以访问 tourist ()

	member(TOURIST, "用户3")
	// 输出:
	// flag:1 & needFlag:10 = 0
	// flag:	 0001
	// needFlag: 0010
	// 与运算结果:0000
	// 用户:用户3 ,无权访问 member

	member(MEMBER, "用户4")
	// 输出:
	// flag:10 & needFlag:10 = 10
	// flag:	 0010
	// needFlag: 0010
	// 与运算结果:0010
	// 用户:用户4, 验证成功,可以访问 member ()

	member(MANAGER, "用户5")
	// 输出:
	// flag:11 & needFlag:10 = 10
	// flag:	 0011
	// needFlag: 0010
	// 与运算结果:0010
	// 用户:用户5, 验证成功,可以访问 member ()
	// 管理员有搬用所有的权限
}

// 游客权限
func tourist(flag int, name string) {
	if !checkAuth(flag, TOURIST|MEMBER) {
		fmt.Printf("用户:%s  无权访问 tourist \n", name)
		return
	} else {
		fmt.Printf("用户:%s 验证成功,可以访问 tourist () \n", name)
	}
}

// 会员
func member(flag int, name string) {
	if !checkAuth(flag, MEMBER) {
		fmt.Printf("用户:%s ,无权访问 member \n", name)
		return
	} else {
		fmt.Printf("用户:%s, 验证成功,可以访问 member () \n", name)
	}
}

func checkAuth(flag int, needFlag int) bool {
	fmt.Printf("\nflag:%b & needFlag:%b = %b \n", flag, needFlag, flag&needFlag)
	return flag&needFlag != 0
}

我们将上面的代码重新过一遍 首先声明权限常量,这里用到了位移运算符和go的iota技巧,

TOURIST: 1 << (iota=0) 刚刚开始的时候,iota的值为0,表示将1左移0位。因为不需要左移,所以TOURIST=0001

MEMBER: 1 << (iota=1) 接下来 iota 变量在遇到第二行的时候,自增累加变成1。表示将1左移1位,所以MEMBER=0010

MANAGER: TOURIST | MEMBER ,最后,将TOURIST和MEMBER进行或运算。我们知道或运算只要有一位为1就为1, 所以MANAGER=(0001 | 0010 ) = 0011

const (
	// 游客
	TOURIST = 1 << iota
	// 会员 1
	MEMBER
	// 管理员
	// 管理拥有所有的权限
	MANAGER = TOURIST | MEMBER
)

接着声明一个tourist函数,表示只要普通游客的权限就可以访问

// 游客权限
func tourist(flag int, name string) {
	// 因为只需要游客的权限,所以普通的会员肯定也有这个权限
	// 这里将TOURIST|MEMBER进行或运算后,访问权限为0011
	// 也就是说,只要找拥有其中任意一个权限的人都可以访问该方法
    if !checkAuth(flag, TOURIST|MEMBER) {
        fmt.Printf("用户:%s 无权访问 tourist \n", name)
        return
    } else {
        fmt.Printf("用户:%s 验证成功,可以访问 tourist () \n", name)
    }
}

// 会员
func member(flag int, name string) {
	// 这里需要会员的权限才可以访问,普通的游客是不能访问的
	if !checkAuth(flag, MEMBER) {
		fmt.Printf("用户:%s ,无权访问 member \n", name)
		return
	} else {
		fmt.Printf("用户:%s, 验证成功,可以访问 member () \n", name)
	}
}

最后我们进行权限验证的最重要的一个函数,这里用到了&与运行符,与运算符和我们常用的 && 差不多,只有两个数为1才为1

func checkAuth(flag int, needFlag int) bool {
	fmt.Printf("\nflag:%b & needFlag:%b = %b \n", flag, needFlag, flag&needFlag)
	// 比如: flag的二进制值为 0001,表示只有游客的权限,需要访问member()方法,而 member() 方法需要0010的权限,
	// 我们将用户拥有的0001权限和访问member()需要的0010权限进行与运算得到 0001 & 0010 = 0000 
	// 二进制 0000 转成10十进制等于0
	// 最终返回false ,表示用户没有访问member()的权限
	return flag&needFlag != 0
}

完毕。。。

dogo 技术交流群:437274005

欢迎加入 dogo 技术交流群:437274005 点击右侧按钮快捷加入 dogo交流群

转载于:https://my.oschina.net/wuciyou/blog/811703

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值