Iris 使用 casbin + gorm 構建許可權
具體專案例項 https://github.com/snowlyg/IrisAdminApi
iris 框架使用 casbin + gorm 構建 api 許可權控制
初始化資料庫和 casbin
關鍵程式碼如下
// models/base.go
import (
"fmt"
"os" "strings"
"IrisAdminApi/transformer" "github.com/casbin/casbin/v2" gormadapter "github.com/casbin/gorm-adapter/v2"
"github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql"
_ "github.com/mattn/go-sqlite3"
)
var Db *gorm.DB
var Enforcer *casbin.Enforcer
var err error
func Register(rc *transformer.Conf) {
var c *gormadapter.Adapter
if isTestEnv() {
c, err = gormadapter.NewAdapter(rc.Sqlite.DirverName, rc.Sqlite.Connect) // Your driver and data source.
if err != nil {
panic(fmt.Sprintf("NewAdapter 錯誤: %v", err))
}
Db, err = gorm.Open(rc.Sqlite.DirverName, rc.Sqlite.Connect)
if err != nil {
panic(fmt.Sprintf("gorm open 錯誤: %v", err))
}
} else {
baseConn := rc.Database.UserName + ":" + rc.Database.Password + "@tcp(" + rc.Database.Addr + ")/"
c, err = gormadapter.NewAdapter(rc.Database.DirverName, baseConn) // Your driver and data source.
if err != nil {
panic(fmt.Sprintf("NewAdapter 錯誤: %v", err))
}
connect := baseConn + rc.Database.Name + "?charset=utf8&parseTime=True&loc=Local"
Db, err = gorm.Open(rc.Database.DirverName, connect)
if err != nil {
panic(fmt.Sprintf("gorm open 錯誤: %v", err))
}
}
Enforcer, err = casbin.NewEnforcer("./config/rbac_model.conf", c)
if err != nil {
panic(fmt.Sprintf("NewEnforcer 錯誤: %v", err))
}
_ = Enforcer.LoadPolicy()
}
//獲取程式執行環境
// 根據程式執行路徑字尾判斷
//如果是 test 就是測試環境
func isTestEnv() bool {
files := os.Args
for _, v := range files {
if strings.Contains(v, "test") {
return true
}
}
return false
}
路由註冊相關中介軟體
// router.go
package routes
import (
"IrisAdminApi/controllers"
"IrisAdminApi/middleware"
"IrisAdminApi/models"
"github.com/betacraft/yaag/irisyaag"
"github.com/kataras/iris/v12"
)
func Register(api *iris.Application) {
main := api.Party("/", middleware.CrsAuth()).AllowMethods(iris.MethodOptions)
{
api.Get("/", func(ctx iris.Context) { // 首頁模組
_ = ctx.View("index.html")
})
api.Get("/apiDoc", func(ctx iris.Context) {
_ = ctx.View("apiDoc/index.html")
})
v1 := main.Party("/v1")
{
v1.Post("/admin/login", controllers.UserLogin)
v1.PartyFunc("/admin", func(admin iris.Party) {
v1.Use(irisyaag.New())
casbinMiddleware := middleware.New(models.Enforcer) //casbin for gorm // <- IMPORTANT, register the middleware.
admin.Use(middleware.JwtHandler().Serve, casbinMiddleware.ServeHTTP) //登入驗證
admin.Get("/logout", controllers.UserLogout).Name = "退出"
admin.PartyFunc("/users", func(users iris.Party) {
users.Get("/", controllers.GetAllUsers).Name = "使用者列表"
users.Get("/{id:uint}", controllers.GetUser).Name = "使用者詳情"
users.Post("/", controllers.CreateUser).Name = "建立使用者"
users.Put("/{id:uint}", controllers.UpdateUser).Name = "編輯使用者"
users.Delete("/{id:uint}", controllers.DeleteUser).Name = "刪除使用者"
users.Get("/profile", controllers.GetProfile).Name = "個人資訊"
})
admin.PartyFunc("/roles", func(roles iris.Party) {
roles.Get("/", controllers.GetAllRoles).Name = "角色列表"
roles.Get("/{id:uint}", controllers.GetRole).Name = "角色詳情"
roles.Post("/", controllers.CreateRole).Name = "建立角色"
roles.Put("/{id:uint}", controllers.UpdateRole).Name = "編輯角色"
roles.Delete("/{id:uint}", controllers.DeleteRole).Name = "刪除角色"
})
admin.PartyFunc("/permissions", func(permissions iris.Party) {
permissions.Get("/", controllers.GetAllPermissions).Name = "許可權列表"
permissions.Get("/{id:uint}", controllers.GetPermission).Name = "許可權詳情"
//permissions.Post("/", controllers.CreatePermission).Name = "建立許可權"
permissions.Post("/import", controllers.ImportPermission).Name = "匯入許可權"
//permissions.Put("/{id:uint}", controllers.UpdatePermission).Name = "編輯許可權"
//permissions.Delete("/{id:uint}", controllers.DeletePermission).Name = "刪除許可權"
})
})
}
}
}
casbin 中介軟體 驗證登入和介面許可權
// middleware/casbin.go
package middleware
import (
"net/http"
"strconv"
"time"
"IrisAdminApi/models"
"github.com/iris-contrib/middleware/jwt"
"github.com/kataras/iris/v12/context"
"github.com/casbin/casbin/v2"
)
/*
Updated for the casbin 2.x released 3 days ago.
2019-07-15
*/
// New returns the auth service which receives a casbin enforcer.
//
// Adapt with its `Wrapper` for the entire application
// or its `ServeHTTP` for specific routes or parties.
func New(e *casbin.Enforcer) *Casbin {
return &Casbin{enforcer: e}
}
// ServeHTTP is the iris compatible casbin handler which should be passed to specific routes or parties.
// Usage:
// [...]
// app.Get("/dataset1/resource1", casbinMiddleware.ServeHTTP, myHandler)
// [...]
func (c *Casbin) ServeHTTP(ctx context.Context) {
value := ctx.Values().Get("jwt").(*jwt.Token)
token := models.GetOauthTokenByToken(value.Raw) //獲取 access_token 資訊
if token.Revoked || token.ExpressIn < time.Now().Unix() {
//_, _ = ctx.Writef("token 失效,請重新登入") // 輸出到前端
ctx.StatusCode(http.StatusUnauthorized)
ctx.StopExecution()
return
} else if !c.Check(ctx.Request(), strconv.FormatUint(uint64(token.UserId), 10)) {
ctx.StatusCode(http.StatusForbidden) // Status Forbidden
ctx.StopExecution()
return
} else {
ctx.Values().Set("auth_user_id", token.UserId)
}
ctx.Next()
}
// Casbin is the auth services which contains the casbin enforcer.
type Casbin struct {
enforcer *casbin.Enforcer
}
// Check checks the username, request's method and path and
// returns true if permission grandted otherwise false.
func (c *Casbin) Check(r *http.Request, userId string) bool {
method := r.Method
path := r.URL.Path
ok, _ := c.enforcer.Enforce(userId, path, method)
return ok
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結