casbin应用
Casbin是一个强大的、高效的开源访问控制架构,其权限管理机制支持多种访问控制模型。
https://casbin.org/docs/zh-CN/overview
Casbin 可以:
l 支持自定义请求的格式,默认的请求格式为{subject, object, action}。
l 具有访问控制模型model和策略policy两个核心概念。
l 支持RBAC中的多层角色继承,不止主体可以有角色,资源也可以具有角色。
l 支持超级用户,如 root 或 Administrator,超级用户可以不受授权策略的约束访问任意资源。
l 支持多种内置的操作符,如 keyMatch,方便对路径式的资源进行管理,如 /foo/bar 可以映射到 /foo*
Casbin 不能:
l 身份认证 authentication(即验证用户的用户名、密码),casbin只负责访问控制。应该有其他专门的组件负责身份认证,然后由casbin进行访问控制,二者是相互配合的关系。
l 管理用户列表或角色列表。 Casbin 认为由项目自身来管理用户、角色列表更为合适, 用户通常有他们的密码,但是Casbin的设计思想并不是把它作为一个存储密码的容器,而是存储RBAC方案中用户和角色之间的映射关系。
基础
Casbin两个核心概念是访问控制模型model和访问控制策略policy,分别对应两个文件:model配置文件和policy策略文件。在 Casbin 中, 访问控制模型model被抽象为基于 PERM (Policy策略, Effect效果, Request请求, Matchers匹配器) 的一个文件,因此切换或升级项目的授权机制与修改配置一样简单。可以通过组合可用的模型来定制访问控制模型。
Model和policy模板可参考:https://casbin.org/docs/zh-CN/supported-models,支持ACL,RBAC,ABAC等。
{subject, object, action}:主体subject表示用户角色,object客体表示访问路径(资源),action表示请求方法。
匹配器定义了策略是如何匹配的,可以通过直接定义实体,或者使用keyMatch方法,也可以匹配通配符。
[request_definition] r = sub, obj, act [policy_definition] p = sub, obj, act // 定义sub可以执行obj资源的act P2 = sub, act //定义sub所有的资源都能执行act [role_definition] // 基于RBAC时需要,定义role g = _, _ //用户和角色 g2 = _, _, //用户、角色、域 [policy_effect] e = some(where (p.eft == allow)) // 有任意一条policy rule满足,则最终结果为allow [matchers] m = r.sub == p.sub && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == "*") //定义request和policy匹配的方式,p.eft是allow还是deny基于此来决定
在安全性方面,通常会选择最简单的解决方案,因为当系统开始变复杂和难以维护时,错误就开始发生。
p, admin, /*, * p, anonymous, /login, * p, member, /logout, * p, member, /member/*, *
Policy配置admin 角色可以访问所有内容,member 角色可以访问以 /member/ 开头的路径和 logout 路径,未认证用户可以登陆。
存储
官网上介绍model只能加载,不能保存。因为作者认为 model 不是动态组件,不应该在运行时进行修改,所以我们没有实现一个 API 来将 model 保存到存储中。提供了三种等效的方法来静态或动态地加载模型:
.CONF文件,代码,字符串
Policy策略存储作为adapter实现(Casbin的中间件) 实现。Casbin用户可以使用adapter从存储中加载策略规则 (aka LoadPolicy()) 或者将策略规则保存到其中 (aka SavePolicy())。 为了保持代码轻量级,没有把adapter代码放在主库中。可参考:https://github.com/HaoweiCh/go-casbin-http-authrozation (mysql policy)
角色管理器用于管理Casbin中的RBAC角色层次结构(用户角色映射)。 角色管理器可以从Casbin策略规则或外部源(如LDAP、Okta、Auth0、Azure AD等) 检索角色数据。 我们支持角色管理器的不同实现。 为了保持代码轻量级,我们没有把角色管理器代码放在主库中(默认的角色管理器除外)。
应用
通常casbin要与身份认证(authorization)如session管理或jwt配合使用。
gin-casbin插件插件使用参考:https://github.com/maxwellhertz/gin-casbin.git
访问资源时需要鉴权中间件判断用户合法性,并分配合适的角色。初步鉴权成功后,将用户角色,请求路径和请求方法传给casbin执行器,执行器根据model和policy确认该角色(subject)的用户是否允许访问该请求方法(action)和路径(object)指定的资源。若校验失败,应返回403,若通过,则继续执行后续处理函数。
参考:在 Go 语言中使用 casbin 实现基于角色的 HTTP 权限控制
一般应用就是两个函数:
1. New a Casbin enforcer with a model file and a policy file: e, _ := casbin.NewEnforcer("path/to/model.conf", "path/to/policy.csv") Note: you can also initialize an enforcer with policy in DB instead of file.
2. Add an enforcement hook into your code right before the access happens: sub := "alice" // the user that wants to access a resource. obj := "data1" // the resource that is going to be accessed. act := "read" // the operation that the user performs on the resource. if res := e.Enforce(sub, obj, act); res { // permit alice to read data1 } else { // deny the request, show an error } 3. Besides the static policy file, Casbin also provides API for permission management at run-time. For example, You can get all the roles assigned to a user as below: roles, _ := e.GetImplicitRolesForUser(sub)
a := mysqladapter.NewDBAdapter("mysql", "mysql_username:mysql_password@tcp(127.0.0.1:3306)/") e := casbin.NewEnforcer("path/to/basic_model.conf", a)
_ = e.LoadPolicy()
数据库结构如下:
mysql> select * from casbin_rule; +--------+------+---------------------------------------------------+--------+------+------+------+ | p_type | v0 | v1 | v2 | v3 | v4 | v5 | +--------+------+---------------------------------------------------+--------+------+------+------+ | p | 8881 | /base/login | POST | | | | | p | 8881 | /base/register | POST | | | | | p | 8881 | /api/createApi | POST | | | |
示例:
package main import ( "errors" "fmt" "log" "net/http" "time" "github.com/casbin/casbin" "github.com/alexedwards/scs/v2" "testcasbin/auth" "testcasbin/model" ) var sessionManager *scs.SessionManager func main() { fmt.Println("hello world") authEnforcer, err := casbin.NewEnforcerSafe("model.conf", "policy.csv") if err != nil { log.Fatal(err) } sessionManager = scs.New() sessionManager.Lifetime = 2 * time.Minute users := createUsers() mux := http.NewServeMux() mux.HandleFunc("/login", loginHandler(users)) mux.HandleFunc("/logout", logoutHandler()) mux.HandleFunc("/member/id", memberHandler()) mux.HandleFunc("/member/role", memberRoleHandler()) mux.HandleFunc("/admin/stuff", adminHandler()) log.Print("Server started on localhost:8088") log.Fatal(http.ListenAndServe(":8088", sessionManager.LoadAndSave(auth.Authorizer(authEnforcer, users, sessionManager)(mux)))) } ... package auth import ( "errors" "log" "net/http" "testcasbin/model" "github.com/alexedwards/scs/v2" "github.com/casbin/casbin" ) func Authorizer(e *casbin.Enforcer, users model.Users, session *scs.SessionManager) func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { var role string var uid int role = session.GetString(r.Context(), "role") if role == "" { role = "anonymous" } if role == "member" { uid = session.GetInt(r.Context(), "userID") if uid == 0 { writeError(http.StatusInternalServerError, "ERROR_NOT_GET_UID", w, errors.New("userID is not in session")) return } exists := users.Exists(uid) if !exists { writeError(http.StatusForbidden, "FORBIDDEN", w, errors.New("user does not exist")) return } } log.Printf("role: %v, uid: %v, path: %v, method: %v\n", role, uid, r.URL.Path, r.Method) res, err := e.EnforceSafe(role, r.URL.Path, r.Method) if err != nil { writeError(http.StatusInternalServerError, "ERROR_CASBIN", w, err) return } if res { next.ServeHTTP(w, r) } else { writeError(http.StatusForbidden, "FORBIDDEN", w, errors.New("unauthorized")) return } } return http.HandlerFunc(fn) } } func writeError(status int, message string, w http.ResponseWriter, err error) { log.Print("ERROR: ", err.Error()) w.WriteHeader(status) w.Write([]byte(message)) }
参考:
1. https://casbin.org/docs/zh-CN/overview 中文文档
2. 在 Go 语言中使用 casbin 实现基于角色的 HTTP 权限控制 基于session身份认证
https://zupzup.org/casbin-http-role-auth/ 英文
3. https://github.com/HaoweiCh/go-casbin-http-authrozation
简单且实用的 HTTP 鉴权体系 (mysql policy + redis session)
4. https://github.com/maxwellhertz/gin-casbin.git gin插件和示例(基于jwt和session)
5. Casbin权限模型 csdn