Go-RBAC: Role and Scope Based Access Control Implementation
This repository demonstrates how to implement Role and Scope-Based Access Control (RBAC) in a Go application using Redis, MySQL, and the Echo framework.
Features π
- Role-Based Access Control: Restricts access to resources based on user roles (e.g., Admin, Employee, Customer).
- Scope-Based Permissions: Adds granular permissions for specific operations (e.g.,
users:read
, users:create
).
- Redis Integration: Caches user roles, scopes and blacklisted access.
- MySQL Integration: Stores user and role data persistently.
- Secure Authentication: Includes endpoints for user registration and login.
Prerequisites π
- Go: Version 1.21 or higher
- MySQL: For storing user data
- Redis: For caching role and scope data
- Docker: For containerization (optional)
Project Structure π
βββ cmd
β βββ main.go # Application entry point
βββ config
β βββ config.go # Configuration loader and management logic
β βββ config.yaml # Configuration file for environment variables and application settings
βββ internal
β βββ {sub_domain} # Grouped by subdomains or modules
β β βββ usecase # Application-specific business logic
β β β βββ usecase.go # Implementation of use cases for the subdomain
β β βββ entities # Core domain entities
β β β βββ entity.go # Definitions of core domain entities
β β βββ dtos # Data Transfer Objects for request/response payloads
β β β βββ dtos.go # DTO definitions for input/output operations
β β βββ repository # Persistence and database layer
β β β βββ repository.go # Implementation of repository interfaces
β β βββ delivery # Delivery layer (e.g., HTTP handlers, routes)
β β β βββ handlers.go # Request/response handlers for the subdomain
β β β βββ routes.go # Route definitions for the subdomain
β β βββ usecase.go # Interface for the use case layer
β β βββ repository.go # Interface for the repository layer
β β βββ delivery.go # Interface for the delivery layer
βββ middleware # Custom middleware (e.g., RBAC, logging, authentication)
βββ pkg # Shared libraries or utility functions
β βββ redis # Utilities for Redis interactions
β βββ constants # Application-wide constants and enumerations
β βββ utils # General utility functions and helpers
β βββ datasources # Data source configuration and initialization (e.g., MySQL, Redis)
β βββ rbac # Role-based access control utilities and logic
βββ migrations # Database migration files
βββ infrastructure # Infrastructure setup and configurations
β βββ docker-compose.yml # Docker Compose configuration for service orchestration
βββ docs # Documentation (e.g., API specifications, design documents)
βββ tests # Testing suite for various layers
β βββ e2e # End-to-end tests
β βββ unit # Unit tests
β βββ integration # Integration tests
βββ README.md # Project documentation
βββ Makefile # Build and automation instructions for the project
Endpoints and Access Requirements π
Endpoint |
HTTP Method |
Scope |
Roles with Access |
Description |
/users |
GET |
users:read |
Admin , Employee |
Retrieve the list of users. |
/users/:id |
PUT |
users:update |
Admin , Employee |
Update user details. |
/users |
POST |
users:create |
Admin |
Create a new user. |
/users/:id |
DELETE |
users:delete |
Admin |
Delete a user. |
/profile |
GET |
profile:read |
Customer , Employee |
Retrieve the authenticated user's profile. |
/profile |
PUT |
profile:update |
Customer , Employee |
Update the authenticated user's profile. |
Installation & Setup π οΈ
Clone the Repository
git clone https://github.com/DoWithLogic/go-rbac.git
cd go-rbac
Run the Application
The make run command will:
- Start the Docker containers for Redis and the database (if not already running).
- Apply any pending database migrations.
- Start the application.
make run
Example Implementation π§βπ»
Middleware for Role Validation
func (m *Middleware) RolesMiddleware(roles ...constants.UserRole) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
jwtData, ok := c.Get(constants.AuthCredentialContextKey.String()).(*security.JWTClaims)
if !ok {
return response.ErrorBuilder(app_errors.Forbidden(app_errors.ErrAccessDenied)).Send(c)
}
if !m.hasRequiredRole(jwtData.Role, roles) {
return response.ErrorBuilder(app_errors.Forbidden(app_errors.ErrAccessDenied)).Send(c)
}
// Store the token claims in the request context for later use
c.Set(constants.AuthCredentialContextKey.String(), jwtData)
return next(c)
}
}
}
func (m *Middleware) hasRequiredRole(userRole constants.UserRole, roles []constants.UserRole) bool {
for _, r := range roles {
if r == userRole {
return true
}
}
return false
}
Middleware for Scope Validation
func (m *Middleware) PermissionsMiddleware(permissions ...constants.Permission) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
jwtData, ok := c.Get(constants.AuthCredentialContextKey.String()).(*security.JWTClaims)
if !ok {
return response.ErrorBuilder(app_errors.Forbidden(app_errors.ErrAccessDenied)).Send(c)
}
if !m.hasRequiredPermission(jwtData.Permissions, permissions) {
return response.ErrorBuilder(app_errors.Forbidden(app_errors.ErrAccessDenied)).Send(c)
}
c.Set(constants.AuthCredentialContextKey.String(), jwtData)
return next(c)
}
}
}
func (m *Middleware) hasRequiredPermission(userPermissions, requiredPermissions []constants.Permission) bool {
requiredPermissionsMap := make(map[constants.Permission]bool)
for _, permission := range requiredPermissions {
requiredPermissionsMap[permission] = true
}
for _, permission := range userPermissions {
if requiredPermissionsMap[permission] {
return true
}
}
return false
}
Assign Middleware to Endpoints
func MapUserRoutes(g echo.Group, h users.Handlers, mw *middlewares.Middleware) {
users := g.Group("/users", mw.JWTMiddleware())
users.POST("", h.CreateUserHandler, mw.RolesMiddleware(constants.AdminUserRole), mw.PermissionsMiddleware(constants.UsersCreatePermission))
}
Configuration βοΈ
App:
Name: "go-rbac"
Version: "0.0.1"
Scheme: "http"
Host: "localhost:3002"
Environment: local #local,development,staging,production
Server:
Port: "3002"
Debug: true
TimeZone: "Asia/Jakarta"
Database:
Host: "127.0.0.1"
Port: "3306"
DBName: "go_rbac"
UserName: "root"
Password: "pwd"
Debug: true
Security:
JWT:
Key: "95476ff7-c7b2-49d7-853e-322b6f983914"
ExpiredInSecond: 3600
API Documentation π
Overview
This repository provides a set of API endpoints for managing roles, permissions, and user access. The API allows you to create, update, retrieve, and delete roles, permissions, and role-permission mappings. It also supports secure JWT-based authentication to enforce role-based access control.
Explore Swagger Documentation
For a detailed description of all the available API endpoints, request/response formats, and examples, explore our Swagger documentation at the following link:
The Swagger documentation will provide detailed information on:
- Available Endpoints: All API routes for managing users, roles, permissions, and access control.
- Request/Response Formats: Detailed format for the expected input and output of each API endpoint.
- Authentication: How to authenticate requests using JWT tokens.
- Role and Permission Validation: How roles and permissions are validated for each endpoint.
License π
This project is licensed under the MIT License. See the LICENSE file for details.
Contributing π€
Feel free to submit pull requests or open issues to improve this project. Contributions are always welcome!
This `README.md` file includes the project overview, structure, setup instructions, endpoint details, and example implementations. Let me know if you'd like to add or modify any sections!