Repository: casbin/casbin
Pull request #1141 (2022-11-27 14:42:14)

feat: add the missing methods like Match(), AddMatchingFunc() and AddDomainMatchingFunc() to the role manager interface
Fix: https://github.com/casbin/casbin/issues/1107

casbin-bot:  @tangyang9464 @JalinWang please review
hsluoyz: Replaced by: https://github.com/casbin/casbin/pull/1142
hsluoyz: @ovargasmahisoft plz review

Patch:
diff --git a/enforcer.go b/enforcer.go
index de25375..22b0673 100644
--- a/enforcer.go
+++ b/enforcer.go
@@ -741,18 +741,18 @@ func (e *Enforcer) BatchEnforceWithMatcher(matcher string, requests [][]interfac
 }
 
 // AddNamedMatchingFunc add MatchingFunc by ptype RoleManager
-func (e *Enforcer) AddNamedMatchingFunc(ptype, name string, fn defaultrolemanager.MatchingFunc) bool {
+func (e *Enforcer) AddNamedMatchingFunc(ptype, name string, fn rbac.MatchingFunc) bool {
 	if rm, ok := e.rmMap[ptype]; ok {
-		rm.(*defaultrolemanager.RoleManager).AddMatchingFunc(name, fn)
+		rm.AddMatchingFunc(name, fn)
 		return true
 	}
 	return false
 }
 
 // AddNamedDomainMatchingFunc add MatchingFunc by ptype to RoleManager
-func (e *Enforcer) AddNamedDomainMatchingFunc(ptype, name string, fn defaultrolemanager.MatchingFunc) bool {
+func (e *Enforcer) AddNamedDomainMatchingFunc(ptype, name string, fn rbac.MatchingFunc) bool {
 	if rm, ok := e.rmMap[ptype]; ok {
-		rm.(*defaultrolemanager.RoleManager).AddDomainMatchingFunc(name, fn)
+		rm.AddDomainMatchingFunc(name, fn)
 		return true
 	}
 	return false
diff --git a/rbac/default-role-manager/role_manager.go b/rbac/default-role-manager/role_manager.go
index 6e69cf8..8939a48 100644
--- a/rbac/default-role-manager/role_manager.go
+++ b/rbac/default-role-manager/role_manager.go
@@ -21,13 +21,12 @@ import (
 
 	"github.com/casbin/casbin/v2/errors"
 	"github.com/casbin/casbin/v2/log"
+	"github.com/casbin/casbin/v2/rbac"
 	"github.com/casbin/casbin/v2/util"
 )
 
 const defaultDomain string = ""
 
-type MatchingFunc func(arg1 string, arg2 string) bool
-
 // Role represents the data structure for a role in RBAC.
 type Role struct {
 	name      string
@@ -168,8 +167,8 @@ func (r *Role) getUsers() []string {
 type RoleManagerImpl struct {
 	allRoles           *sync.Map
 	maxHierarchyLevel  int
-	matchingFunc       MatchingFunc
-	domainMatchingFunc MatchingFunc
+	matchingFunc       rbac.MatchingFunc
+	domainMatchingFunc rbac.MatchingFunc
 	logger             log.Logger
 	matchingFuncCache  *util.SyncLRUCache
 }
@@ -185,7 +184,7 @@ func NewRoleManagerImpl(maxHierarchyLevel int) *RoleManagerImpl {
 }
 
 // use this constructor to avoid rebuild of AddMatchingFunc
-func newRoleManagerWithMatchingFunc(maxHierarchyLevel int, fn MatchingFunc) *RoleManagerImpl {
+func newRoleManagerWithMatchingFunc(maxHierarchyLevel int, fn rbac.MatchingFunc) *RoleManagerImpl {
 	rm := NewRoleManagerImpl(maxHierarchyLevel)
 	rm.matchingFunc = fn
 	return rm
@@ -276,13 +275,13 @@ func (rm *RoleManagerImpl) removeRole(name string) {
 }
 
 // AddMatchingFunc support use pattern in g
-func (rm *RoleManagerImpl) AddMatchingFunc(name string, fn MatchingFunc) {
+func (rm *RoleManagerImpl) AddMatchingFunc(name string, fn rbac.MatchingFunc) {
 	rm.matchingFunc = fn
 	rm.rebuild()
 }
 
 // AddDomainMatchingFunc support use domain pattern in g
-func (rm *RoleManagerImpl) AddDomainMatchingFunc(name string, fn MatchingFunc) {
+func (rm *RoleManagerImpl) AddDomainMatchingFunc(name string, fn rbac.MatchingFunc) {
 	rm.domainMatchingFunc = fn
 }
 
@@ -439,8 +438,8 @@ func (rm *RoleManagerImpl) BuildRelationship(name1 string, name2 string, domain
 type DomainManager struct {
 	rmMap              *sync.Map
 	maxHierarchyLevel  int
-	matchingFunc       MatchingFunc
-	domainMatchingFunc MatchingFunc
+	matchingFunc       rbac.MatchingFunc
+	domainMatchingFunc rbac.MatchingFunc
 	logger             log.Logger
 	matchingFuncCache  *util.SyncLRUCache
 }
@@ -460,7 +459,7 @@ func (dm *DomainManager) SetLogger(logger log.Logger) {
 }
 
 // AddMatchingFunc support use pattern in g
-func (dm *DomainManager) AddMatchingFunc(name string, fn MatchingFunc) {
+func (dm *DomainManager) AddMatchingFunc(name string, fn rbac.MatchingFunc) {
 	dm.matchingFunc = fn
 	dm.rmMap.Range(func(key, value interface{}) bool {
 		value.(*RoleManagerImpl).AddMatchingFunc(name, fn)
@@ -469,7 +468,7 @@ func (dm *DomainManager) AddMatchingFunc(name string, fn MatchingFunc) {
 }
 
 // AddDomainMatchingFunc support use domain pattern in g
-func (dm *DomainManager) AddDomainMatchingFunc(name string, fn MatchingFunc) {
+func (dm *DomainManager) AddDomainMatchingFunc(name string, fn rbac.MatchingFunc) {
 	dm.domainMatchingFunc = fn
 	dm.rmMap.Range(func(key, value interface{}) bool {
 		value.(*RoleManagerImpl).AddDomainMatchingFunc(name, fn)
diff --git a/rbac/role_manager.go b/rbac/role_manager.go
index ac895df..18b4ca8 100644
--- a/rbac/role_manager.go
+++ b/rbac/role_manager.go
@@ -20,6 +20,8 @@ import (
 	"github.com/casbin/casbin/v2/log"
 )
 
+type MatchingFunc func(arg1 string, arg2 string) bool
+
 // RoleManager provides interface to define the operations for managing roles.
 type RoleManager interface {
 	// Clear clears all stored data and resets the role manager to the initial state.
@@ -49,6 +51,12 @@ type RoleManager interface {
 	PrintRoles() error
 	// SetLogger sets role manager's logger.
 	SetLogger(logger log.Logger)
+	// Match matches the domain with the pattern
+	Match(str string, pattern string) bool
+	// AddMatchingFunc adds the matching function
+	AddMatchingFunc(name string, fn MatchingFunc)
+	// AddDomainMatchingFunc adds the domain matching function
+	AddDomainMatchingFunc(name string, fn MatchingFunc)
 }
 
 // RoleManagerWithContext provides a context-aware interface to define the operations for managing roles.
diff --git a/rbac_api.go b/rbac_api.go
index 9c5b72e..7a44311 100644
--- a/rbac_api.go
+++ b/rbac_api.go
@@ -17,7 +17,6 @@ package casbin
 import (
 	"github.com/casbin/casbin/v2/constant"
 	"github.com/casbin/casbin/v2/errors"
-	"github.com/casbin/casbin/v2/rbac/default-role-manager"
 	"github.com/casbin/casbin/v2/util"
 )
 
@@ -308,7 +307,7 @@ func (e *Enforcer) GetNamedImplicitPermissionsForUser(ptype string, user string,
 			return nil, errors.ERR_DOMAIN_PARAMETER
 		} else {
 			d := domain[0]
-			matched := rm.(*defaultrolemanager.RoleManager).Match(d, rule[domainIndex])
+			matched := rm.Match(d, rule[domainIndex])
 			if !matched {
 				continue
 			}


Test patch:
diff --git a/model_test.go b/model_test.go
index 072e894..f2c3437 100644
--- a/model_test.go
+++ b/model_test.go
@@ -366,6 +366,10 @@ func (rm *testCustomRoleManager) GetAllDomains() ([]string, error) {
 func (rm *testCustomRoleManager) PrintRoles() error           { return nil }
 func (rm *testCustomRoleManager) SetLogger(logger log.Logger) {}
 
+func (rm *testCustomRoleManager) Match(str string, pattern string) bool                   { return true }
+func (rm *testCustomRoleManager) AddMatchingFunc(name string, fn rbac.MatchingFunc)       {}
+func (rm *testCustomRoleManager) AddDomainMatchingFunc(name string, fn rbac.MatchingFunc) {}
+
 func TestRBACModelWithCustomRoleManager(t *testing.T) {
 	e, _ := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
 	e.SetRoleManager(NewRoleManager())
diff --git a/rbac_api_test.go b/rbac_api_test.go
index 236dba4..e604572 100644
--- a/rbac_api_test.go
+++ b/rbac_api_test.go
@@ -20,7 +20,6 @@ import (
 	"testing"
 
 	"github.com/casbin/casbin/v2/errors"
-	defaultrolemanager "github.com/casbin/casbin/v2/rbac/default-role-manager"
 	"github.com/casbin/casbin/v2/util"
 )
 
@@ -307,7 +306,7 @@ func TestImplicitRoleAPI(t *testing.T) {
 
 	e, _ = NewEnforcer("examples/rbac_with_pattern_model.conf", "examples/rbac_with_pattern_policy.csv")
 
-	e.GetRoleManager().(*defaultrolemanager.RoleManager).AddMatchingFunc("matcher", util.KeyMatch)
+	e.GetRoleManager().AddMatchingFunc("matcher", util.KeyMatch)
 	e.AddNamedMatchingFunc("g2", "matcher", util.KeyMatch)
 
 	//testGetImplicitRoles(t, e, "cathy", []string{"/book/1/2/3/4/5", "pen_admin", "/book/*", "book_group"})