需求整理
- 管理后台有超管权限,超管拥有所有权限
- 普通管理员可以设置角色,角色单选
- 角色可以赋予多个权限,权限多选
- 这样我们就实现了对普通管理员的角色和权限的灵活管理
文档说明
- 基于golang语言开发
- 基于gin网络框架开发
- 基于MySQL5.8开发
- 把权限管理部分封装成中间件,在rourter文件中引用
- 非核心代码已省略,用3个竖着排列的点号.表示
数据库表结构设计
管理员表
权限表
角色表
角色表permission字段示意
代码部分
路由文件
package server
import (
.
.
.
"os"
"github.com/gin-gonic/gin"
)
// NewRouter 路由配置
func NewRouter() *gin.Engine {
r := gin.Default()
// 其他中间件
.
.
.
// 路由
v1 := r.Group("/api/v1")
{
v1.POST("login", api.Login)
auth := v1.Group("")
//登录校验中间件
auth.Use(middleware.AuthRequired())
//关键代码:权限角色校验
auth.Use(middleware.AuthCheckMiddleware)
{
.
.
.
// 获取所有学校
{
auth.GET("/school/", api.GetSchoolInfo)
}
.
.
.
}
}
return r
}
权限校验中间件代码
package middleware
import (
.
.
.
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"strings"
)
var AuthCheckMiddleware = authCheck()
func authCheck() gin.HandlerFunc {
return func(c *gin.Context) {
if admin, _ := c.Get("admin"); admin != nil {
method := c.Request.Method
url := c.Request.URL.Path
adminInfo := admin.(**service.RunningClaims)
isSuper := (*adminInfo).IsSuper //是否是超管
roleId := (*adminInfo).RoleId
if isSuper != 1 {
fmt.Println("method:", method)
fmt.Println("url:", url)
permissionFunc := strings.ToLower(fmt.Sprintf("%s_%s", method, url))
haveAuth := model.CheckRolePermission(uint(roleId), permissionFunc)
fmt.Println("haveAuth ", haveAuth)
if !haveAuth {
c.JSON(http.StatusOK, api.ReturnJson{http.StatusForbidden, "", "无权访问"})
c.Abort()
}
}
c.Next()
}
}
}
角色model层代码
- CheckRolePermission是关键代码
//角色部分
type StringArray []string
//角色
type Role struct {
Id int `gorm:"column:id" form:"id" json:"id" comment:"自增id" sql:"int(11),PRI"`
Name string `gorm:"column:name" form:"name" json:"name" comment:"角色名" sql:"varchar(255)"`
Description string `gorm:"column:description" form:"description" json:"description" comment:"描述" sql:"varchar(255)"`
Permission *StringArray `gorm:"type:json;column:permission" form:"permission" json:"permission" comment:"权限"`
}
func (data *StringArray) Scan(val interface{}) (err error) {
if val == nil {
return nil
}
if payload, ok := val.([]byte); ok {
var value []string
err = json.Unmarshal(payload, &value)
if err == nil {
*data = value
}
}
return
}
func CheckRolePermission(roleId uint, permissionFunc string) bool {
if roleId == 0 {
return false
}
var myRole Role
err := DB.Where("id = ?", roleId).First(&myRole).Error
if err != gorm.ErrRecordNotFound {
fmt.Printf("%v", myRole)
permissions := myRole.Permission
permissions.Scan(permissions)
for _, permission := range *permissions {
fmt.Println("permissionFunc:", permissionFunc)
fmt.Println("permission:", permission)
if strings.HasPrefix(permissionFunc, permission) {
return true
}
}
}
return false
}
运行效果
有权限
{
"code": 403,
"data": "",
"message": "无权访问"
}
无权限
{
"code": 200,
"data": true,
"message": "更新成功"
}
后续
下一章封装管理后台的操作日志管理:以中间件+goroutine的方式保存管理员的操作日志