系统设计(自动化权限)
权限
自动化权限
准备知识:swagger、递归、注解、过滤器
设计
权限是每一个管理系统必备的一个功能,多租用户设计必备,虽然有很多集成框架工具包比如:“
Casbin
、GRABC
”,但是其怎么判断其实原理都是一样的
表结构说明
- 用户表和用户与角色中间表:无论是超级管理员添加的还是注册用户都会有一个角色初始权限。如果是超级管理员添加添加是可以指定那些角色,角色中有哪些权限,如果是
App
用户注册的有哪些权限注册时会初始化一个最初权限,可以通过开通会员,或者做任务升级拥有想应得角色。在此可能会产生一个用户多个角色,所以会有用户表与角色中间表来记录 - 资源表:可以使用 swagger 工具与注解,在启动是扫描所有接口并且通过递归解析
swagger.json
文件,初始化所有接口名称与接口url
,插入表中 - 角色表:在程序初始化时需要,在表中初始默认角色,或者管理员用户添加角色时选择相应资源
执行步骤
http
请求过滤器校验- 获取
token
其中用户唯一标识,以及用户http
请求的url
- 通过用户唯一标识查询用户角色 ,获取用户角色唯一标识
- 通过角色唯一标识和
url
查询资源表是否有对应的资源(url
) - 如果有忽略,没有则返回,没有对应权限
注解
在控制器接口以及路由文件中添加
1
2
3
4
5
6
7
8
9
// Login 用户登录
// @Tags 登录管理
// @Summary 用户登录
// @Param body body schema.LoginParam true "请求参数"
// @Success 200 {object} schema.LoginTokenInfo
// @Failure 400 {object} schema.HTTPError "{error:{code:0,message:无效的请求参数}}"
// @Failure 500 {object} schema.HTTPError "{error:{code:0,message:服务器错误}}"
// @Router /api/v1/pub/login [post]
func (a *Login) Login(c *gin.Context) {}
swagger
-
下载
swagger
工具添加,Go
环境的bin
目录下 -
进入项目根目录
swag init
生成或者使用以下方式1 2 3
go get -u github.com/swaggo/swag/cmd/swag swag init -g ./internal/app/routers/swagger.go -o ./docs/swagger swag init -g ./internal/app/routers/swagger.go -o ./docs/swagger/
-
会生成
docs
目录 里面有1 2 3
|-- docs.go |-- swagger.json |-- swagger.yaml
递归解析
- 需要在
main
方法调用函数启动解析 - 递归解析代码如下
demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package main
import (
"encoding/json"
"io/ioutil"
"strings"
"github.com/Cc360428/HelpPackage/UtilsHelp/logs"
"github.com/Cc360428/HelpPackage/result"
)
func main() {
// 所在 swagger.json 路径
GetFile("swagger.json")
}
type Resource struct {
Name string `json:"name"` //名称
Url string `json:"url"` //路径
}
func SwaggerJson(swagger string) (a map[string]interface{}) {
xxx := make(map[string]interface{})
bytes, err := ioutil.ReadFile(swagger)
if err != nil {
logs.Error(err.Error())
}
err = json.Unmarshal(bytes, &xxx)
if err != nil {
logs.Error("error", err.Error())
}
birds := xxx["paths"].(map[string]interface{})
// logs.Info("返回 映射", birds)
return birds
}
func GetOpId(vv interface{}) (ret interface{}) {
dd := make(map[string]interface{})
_ = result.HelperConvetInterface(vv, &dd)
for kk, value := range dd {
if kk == "summary" {
ret = value
return value
} else {
ret = GetOpId(value)
if ret != nil {
return ret
}
}
}
return nil
}
func GetFile(path string) {
birds := SwaggerJson(path)
var pps []*Resource
for url, value := range birds {
name := GetOpId(value)
var pp Resource
pp.Url = url
_ = result.HelperConvetInterface(name, &pp.Name)
pps = append(pps, &pp)
n := InterfaceTurnString(name)
// 这里会根据自定义 符号分割
// t := SplitUtil(n, ".")
_, _ = PowerAddOne(n, url)
}
}
func PowerAddOne(name, url string) (id int64, err error) {
logs.Info(name, url)
return
//保存到数据库
}
//字符串分割
//第一个参数为要分割的字符串,第二个参数为分割的条件
//返回分割后的数组
func SplitUtil(parameter string, condition string) []string {
str := strings.Split(parameter, condition)
return str
}
//interface 转 string
func InterfaceTurnString(pr interface{}) string {
s := pr.(string)
return s
}
This post is licensed under
CC BY 4.0
by the author.