beego后台权限管理
博客系统的开发离不开一个后台管理系统,其实很多系统,都需要一个后台,后台的一个很重要模块,就是权限管理,经典的权限管理是rbac权限管理。
本文参照rbac,做了一个自己的权限管理系统。接上文,使用beego框架,建立User模型,操作数据库,执行登陆操作。,基于上篇文章中用户登陆。
rbac又叫做:Role-Based Access Control。核心含义为:权限与角色相关,用户属于某一种或者多中角色,从而得到这些权限。将权限赋予给角色,角色赋予给用户。
建立数据库表结构
通过面的描述可知,肯定存在的三个entity为用户,角色,权限,以及这三者存在的关系用户和角色的关系,角色和权限的关系。分别命名如下:
用户表 -> 对应的在mysql中的数据库表为user
角色表 -> 对应在mysql中的数据库表为role
权限表 -> 对应mysql中的adminmenu表:这里说明一下:我们的后台权限管理到菜单,权限最直接的体现就是菜单,所以权限表就是菜单表。之所以不用menu,是为了区分前后台,这里的菜单只要指后台菜单
用户角色表 -> 用户和角色的关系表,用户id和角色id是一种多对多的关系 mysql中的名字为:roleuser
角色权限表 -> 用户和权限之间,一种多对多的关系,mysql中的名字为:rolemenu
在创建了数据库后,需要在beego中定义对应的模型
建立beego中的model
user模型 模型中的字段属性以及 struct tag的定义和 上面定义的mysql数据库表结构保持一致。
type User struct {
Id int `orm:"column(id);auto;pk" description:"用户Id"`
Name string `orm:"column(name);size(255)" description:"名字"`
Password string `orm:"column(password);size(255)" description:"密码"`
Email string `orm:"column(email);size(255)" description:"邮箱"`
Created time.Time `orm:"auto_now_add;type(datetime)"`
Status int `orm:"column(status)" description:"当前用户的状态"`
}
角色的模型定义Role
type Role struct {
Id int `orm:"column(id);auto;pk" description:"角色Id"`
Name string `orm:"column(name);size(255)" description:"角色名称"`
Des string `orm:"column(des);size(255)" description:"角色描述"`
}
菜单或者叫做权限的模型定义
type AdminMenu struct {
Id int `orm:"column(id);auto;pk" description:"后台的菜单Id"`
Title string `orm:"column(title);size(255)" description:"后台菜单的名字"`
MenuIcon string `orm:"column(menuicon);size(255);null" description:"菜单使用icon"`
Target string `orm:"column(target);size(255)" description:"打开方式"`
Url string `orm:"column(url);size(255)" description:"打开链接的url"`
Sort int `orm:"column(sort)" description:"同级别的排序"`
Pid int `orm:"column(pid)" description:"父节点的菜单"`
}
用户和角色的对应关系模型,很简单,一个自增的主键,一个角色id,一个用户id,角色id和用户id是一种多对多的关系。
type RoleUser struct {
Id int `orm:"column(id);auto;pk" description:"用户角色Id"`
RoleId int `orm:"column(roleid)" description:"角色Id"`
UserId int `orm:"column(userid)" description:"用户Id"`
}
同理角色和权限的管理模型和用户和角色的模型类似
type RoleMenu struct {
Id int `orm:"column(id);auto;pk" description:"角色权限的自增Id"`
RoleId int `orm:"column(roleid)" description:"角色Id"`
AdminMenuId int `orm:"column(adminmenuid)" description:"菜单对应的id"`
}
增加请求路由
权限管理首先要用户已经登录,并且将登录信息user存到session中。用户登陆成功后,在请求后台主页的时候,根据session中用户,查找用户角色,根据用户角色查找用户拥有那些权限,也就是可以使用的菜单,在web上将用户的菜单显示出来。
增加路由:/admin/user/menuinfo请求
beego.Router("/admin/user/menuinfo",&admin.IndexController{},"Get:GetMenuTree")
具体的渲染这里不再描述,有很多框架和管理后台模板都可以做渲染。这里仅仅返回一个json的数据格式。
树形菜单数据结构的生成,最终以json格式返回
根据登陆时候存入session中的user,能够获取到对应的userId。
根据userId获取用户所属的角色,能够查找到对应的角色id
根据用户的角色id 查找该角色对应的菜单id,应该可以查找出来一个数组。
具体在beego中怎么查找一个模型,怎么根据查询条件,查询模型。后面章节会,仔细记录一个beego中的orm操作。
通过上面的操作,已经可以获取到一个菜单数据,但是这个菜单数据为一个数组,那个菜单是那个菜单的上级,那个菜单是那个菜单的子节点。需要分析出来。否则html无法渲染。下面说明一下:怎么根据菜单数据(数组)生成树状结构。
定义一个树形的数据结构,
type MenuTree struct {
Menu *admin.AdminMenu //这是查询到的所有的菜单 model 数据
Childs []*MenuTree //该菜单的子节点。那些菜单项在该节点下
Parent *MenuTree //该菜单的父节点
}
/*
根据数据库表中的数据组装成一个树状菜单
这里不考虑层级 其实只有三个级别
这是一个纯算法问题。
[root1] [root2] [root3]
child1 child2 child1 child2 chaild1 child2
*/
func GenerateMenuTree(menuArr []*admin.AdminMenu)(tree []*MenuTree){
//itemArr := make([] *MenuTree,0)
itemMap := make(map[int]*MenuTree)
for _,v := range menuArr{
itemMap[v.Id] = &MenuTree{Menu:v}
}
headArr := make([] *MenuTree,0)
//经过本次遍历,所有的子节点都找到了父节点,所有的父节点也都找到了子节点
for _,v := range itemMap{
childs := GetChildMenuByPId(itemMap,v.Menu.Id)
v.Childs = GetChildMenuByPId(itemMap,v.Menu.Id)
for i := 0;i< len(childs);i++{
childs[i].Parent = v
}
}
//查找到根节点
for _,v := range itemMap{
if v.Parent == nil{
headArr = append(headArr, v)
}
}
DoSort(headArr)
tree = headArr
return
}
上面的逻辑,能够将一个菜单的数据装换成为一个属性结构。通过遍历属性结构,生成有属性结构的json数据。
上面能够实现权限管理的基本功能,下面的章节将一点一点补充,每一个操作,每个路由。