all posts
2025-05-07 · 4 min read

Casbin: access control in go. Part 1

Welcome everyone! After a long break caused by turbulent events in my life, I finally found time and inspiration to complete the series of articles about access control using Casbin. In this second and final part, we'll dive into practical implementation and look at a specific example of using this powerful library together with my own open-source project Guard.

Despite having limited time for writing technical articles lately, I continued working on tools that can make life easier for Go developers. And today I'm happy to share the results of this work with you.

Introduction

In the previous part, we looked at basic concepts of access control and different approaches to its implementation. Now we'll focus on the practical implementation of a three-level access control system using Casbin.

Open-source project "Guard"

Guard is a library that simplifies working with Casbin in Go projects and provides a convenient interface for implementing access control.

Code on Github

https://github.com/nesymno/guard

So, Guard provides its own factory for creating multi-level authorization, which significantly simplifies working with Casbin in Go. This implementation covers most typical use cases.

Additionally, Guard allows creating custom authorization implementations through the Factory interface:

go
type Factory interface {
    Scope(data ScopeData) Scope
    SubjectUser(id string) Subject
    SubjectRole(tenantID, id string) Subject
    SubjectGroup(tenantID, id string) Subject
    Object(s Scope, p Perm) Object
    GroupPolicy(sub, role Subject) GroupPolicy
    PolicyFromCasbin(p []string) (Policy, error)
    RolePolicyFromCasbin(p []string) (RolePolicy, error)
    RolePoliciesFromCasbin(p [][]string) ([]RolePolicy, error)
    GroupPolicyFromCasbin(p []string) (GroupPolicy, error)
}

This interface provides the ability to:

  • Create custom scopes to limit access context
  • Define different types of subjects: users, roles, and groups
  • Configure access objects and their policies
  • Convert Casbin rules to Guard format and vice versa

Thanks to this flexibility, you as developers can adapt Guard to your project's specific needs while maintaining all the benefits of using Casbin.

Usage Example

Let's look at an example of using Guard. Just go to the guard/examples/tenant/main.go file and review it:

go
func main() {
    // Create a new Guard factory
    f := guard.NewFactory()
 
    // Create a scope for tenant with ID "1"
    s := f.Scope(guard.ScopeData{TenantID: "1"})
 
    // Create a user with ID "user1"
    user := f.SubjectUser("user1")
 
    // Create "admin" role for tenant "1"
    role := f.SubjectRole("1", "admin")
 
    // Create a group policy that assigns the role to the user
    groupPolicy := f.GroupPolicy(user, role)
 
    // Create "resource1" object with "read" permission
    obj := f.Object(s, guard.Read)
 
    // Create a policy that allows admin role to read the resource
    policy := guard.NewPolicy(role, obj)
 
    // Initialize Casbin enforcer
    e, _ := casbin.NewEnforcer("examples/tenant/model.conf")
 
    // Add policies to enforcer
    e.AddPolicy(policy.ToCasbin()...)
    e.AddGroupingPolicy(groupPolicy.ToCasbin()...)
 
    // Check access
    ok, _ := e.Enforce(user.String(), s.String(), "resource1", "read")
    fmt.Printf("Access granted: %v\n", ok)
}

Let's break down this example step by step

  1. A new Guard factory is created, which provides methods for creating all necessary components
  2. A scope is defined for a specific tenant (organization), allowing isolation of access rules between different organizations
  3. Subjects are created: user and role
  4. Role is assigned to user through group policy
  5. An object is created with specific access right (in this case - reading)
  6. A policy is created that allows admin role to read the resource
  7. All policies are converted to Casbin format and added to enforcer
  8. User's access is verified

Main features of Guard library

✓ Multi-level access control system (users, roles, groups)

✓ Multi-tenancy support through scopes

✓ Convenient interface for working with Casbin

✓ Type safety through using Go structures instead of strings

✓ Extensibility through custom factory implementations

✓ Easy integration with existing Go projects

The library significantly simplifies working with Casbin, providing a convenient API for typical use cases while maintaining flexibility and extensibility of the base functionality.

Tests

Writing tests was my biggest pain point. They require a lot of work, lots of mocks, and it's difficult to track and remember everything. Still, it needed to be done so I could share it with you.

Coverage of main structure that contains all necessary methods

Coverage of main structure that contains all necessary methods

Conclusion

In this article, we looked at the practical implementation of access control using the Guard library, which significantly simplifies working with Casbin in Go projects. We saw how easy it is to set up a multi-level authorization system using users, roles, and groups.

Guard provides not only a convenient API for typical use cases but also the possibility of extension through custom factory implementations. This makes the library flexible enough for use in various projects, from small applications to complex enterprise systems.

Although developing and testing such an access control system can be a challenging task, using Guard significantly simplifies this process by providing a type-safe and intuitive interface for working with Casbin.