您的位置:首页 > 编程语言 > Go语言

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

2016-12-25 00:00 274 查看
今天分享的是使用二进制权限控制。

我们在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 点击右侧按钮快捷加入


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Go dogo