Iris 使用 casbin + gorm 構建許可權

snowlyg發表於2020-01-11

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 協議》,轉載必須註明作者和本文連結

相關文章