Post

系统设计(自动化权限)

权限

自动化权限

准备知识:swagger、递归、注解、过滤器

设计

权限是每一个管理系统必备的一个功能,多租用户设计必备,虽然有很多集成框架工具包比如:“CasbinGRABC”,但是其怎么判断其实原理都是一样的

权限数据图

表结构说明

  • 用户表和用户与角色中间表:无论是超级管理员添加的还是注册用户都会有一个角色初始权限。如果是超级管理员添加添加是可以指定那些角色,角色中有哪些权限,如果是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.