|
1 |
| -# go-rbac |
2 |
| -go-rbac is a lightweight and scalable library for implementing Role-Based Access Control (RBAC) in Go applications. It provides an intuitive and flexible way to define roles, permissions, and access scopes to secure your APIs and application resources. |
| 1 | +# Go-RBAC: Role and Scope Based Access Control Implementation |
| 2 | + |
| 3 | +This repository demonstrates how to implement **Role and Scope-Based Access Control (RBAC)** in a Go application using **Redis**, **MySQL**, and the Echo framework. |
| 4 | + |
| 5 | +<p align="center"> |
| 6 | + <img src="docs/rbac.png" alt="rbac" /> |
| 7 | +</p> |
| 8 | + |
| 9 | +--- |
| 10 | + |
| 11 | +## Features 🚀 |
| 12 | + |
| 13 | +- **Role-Based Access Control**: Restricts access to resources based on user roles (e.g., Admin, Employee, Customer). |
| 14 | +- **Scope-Based Permissions**: Adds granular permissions for specific operations (e.g., `users:read`, `users:create`). |
| 15 | +- **Redis Integration**: Caches user roles, scopes and blacklisted access. |
| 16 | +- **MySQL Integration**: Stores user and role data persistently. |
| 17 | +- **Secure Authentication**: Includes endpoints for user registration and login. |
| 18 | + |
| 19 | +--- |
| 20 | + |
| 21 | +## Prerequisites 📋 |
| 22 | + |
| 23 | +- **Go**: Version 1.21 or higher |
| 24 | +- **MySQL**: For storing user data |
| 25 | +- **Redis**: For caching role and scope data |
| 26 | +- **Docker**: For containerization (optional) |
| 27 | + |
| 28 | +--- |
| 29 | + |
| 30 | +## Project Structure 📂 |
| 31 | +```bash |
| 32 | +├── cmd |
| 33 | +│ └── main.go # Application entry point |
| 34 | +├── config |
| 35 | +│ ├── config.go # Configuration loader and management logic |
| 36 | +│ └── config.yaml # Configuration file for environment variables and application settings |
| 37 | +├── internal |
| 38 | +│ ├── {sub_domain} # Grouped by subdomains or modules |
| 39 | +│ │ ├── usecase # Application-specific business logic |
| 40 | +│ │ │ └── usecase.go # Implementation of use cases for the subdomain |
| 41 | +│ │ ├── entities # Core domain entities |
| 42 | +│ │ │ └── entity.go # Definitions of core domain entities |
| 43 | +│ │ ├── dtos # Data Transfer Objects for request/response payloads |
| 44 | +│ │ │ └── dtos.go # DTO definitions for input/output operations |
| 45 | +│ │ ├── repository # Persistence and database layer |
| 46 | +│ │ │ └── repository.go # Implementation of repository interfaces |
| 47 | +│ │ ├── delivery # Delivery layer (e.g., HTTP handlers, routes) |
| 48 | +│ │ │ ├── handlers.go # Request/response handlers for the subdomain |
| 49 | +│ │ │ └── routes.go # Route definitions for the subdomain |
| 50 | +│ │ ├── usecase.go # Interface for the use case layer |
| 51 | +│ │ ├── repository.go # Interface for the repository layer |
| 52 | +│ │ ├── delivery.go # Interface for the delivery layer |
| 53 | +├── middleware # Custom middleware (e.g., RBAC, logging, authentication) |
| 54 | +├── pkg # Shared libraries or utility functions |
| 55 | +│ ├── redis # Utilities for Redis interactions |
| 56 | +│ ├── constants # Application-wide constants and enumerations |
| 57 | +│ ├── utils # General utility functions and helpers |
| 58 | +│ ├── datasources # Data source configuration and initialization (e.g., MySQL, Redis) |
| 59 | +│ └── rbac # Role-based access control utilities and logic |
| 60 | +├── migrations # Database migration files |
| 61 | +├── infrastructure # Infrastructure setup and configurations |
| 62 | +│ └── docker-compose.yml # Docker Compose configuration for service orchestration |
| 63 | +├── docs # Documentation (e.g., API specifications, design documents) |
| 64 | +├── tests # Testing suite for various layers |
| 65 | +│ ├── e2e # End-to-end tests |
| 66 | +│ ├── unit # Unit tests |
| 67 | +│ └── integration # Integration tests |
| 68 | +├── README.md # Project documentation |
| 69 | +└── Makefile # Build and automation instructions for the project |
| 70 | +``` |
| 71 | + |
| 72 | +## Endpoints and Access Requirements 🌐 |
| 73 | +| Endpoint | HTTP Method | Scope | Roles with Access | Description | |
| 74 | +|-------------------|-------------|-----------------|------------------------|------------------------------------------| |
| 75 | +| `/users` | `GET` | `users:read` | `Admin`, `Employee` | Retrieve the list of users. | |
| 76 | +| `/users/:id` | `PUT` | `users:update` | `Admin`, `Employee` | Update user details. | |
| 77 | +| `/users` | `POST` | `users:create` | `Admin` | Create a new user. | |
| 78 | +| `/users/:id` | `DELETE` | `users:delete` | `Admin` | Delete a user. | |
| 79 | +| `/profile` | `GET` | `profile:read` | `Customer`, `Employee` | Retrieve the authenticated user's profile.| |
| 80 | +| `/profile` | `PUT` | `profile:update`| `Customer`, `Employee` | Update the authenticated user's profile. | |
| 81 | +--- |
| 82 | + |
| 83 | +## Installation & Setup 🛠️ |
| 84 | + |
| 85 | +### Clone the Repository |
| 86 | +```bash |
| 87 | +git clone https://github.com/DoWithLogic/go-rbac.git |
| 88 | +cd go-rbac |
| 89 | +``` |
| 90 | + |
| 91 | +### Run the Application |
| 92 | +The make run command will: |
| 93 | +- Start the Docker containers for Redis and the database (if not already running). |
| 94 | +- Apply any pending database migrations. |
| 95 | +- Start the application. |
| 96 | +```bash |
| 97 | +make run |
| 98 | +``` |
| 99 | + |
| 100 | + |
| 101 | +## Example Implementation 🧑💻 |
| 102 | +### Middleware for Role Validation |
| 103 | +```bash |
| 104 | +func (m *Middleware) RolesMiddleware(roles ...constants.UserRole) echo.MiddlewareFunc { |
| 105 | + return func(next echo.HandlerFunc) echo.HandlerFunc { |
| 106 | + return func(c echo.Context) error { |
| 107 | + jwtData, ok := c.Get(constants.AuthCredentialContextKey.String()).(*security.JWTClaims) |
| 108 | + if !ok { |
| 109 | + return response.ErrorBuilder(app_errors.Forbidden(app_errors.ErrAccessDenied)).Send(c) |
| 110 | + } |
| 111 | + |
| 112 | + if !m.hasRequiredRole(jwtData.Role, roles) { |
| 113 | + return response.ErrorBuilder(app_errors.Forbidden(app_errors.ErrAccessDenied)).Send(c) |
| 114 | + } |
| 115 | + |
| 116 | + // Store the token claims in the request context for later use |
| 117 | + c.Set(constants.AuthCredentialContextKey.String(), jwtData) |
| 118 | + |
| 119 | + return next(c) |
| 120 | + } |
| 121 | + } |
| 122 | +} |
| 123 | + |
| 124 | +func (m *Middleware) hasRequiredRole(userRole constants.UserRole, roles []constants.UserRole) bool { |
| 125 | + for _, r := range roles { |
| 126 | + if r == userRole { |
| 127 | + return true |
| 128 | + } |
| 129 | + } |
| 130 | + return false |
| 131 | +} |
| 132 | +``` |
| 133 | +### Middleware for Scope Validation |
| 134 | +```bash |
| 135 | +func (m *Middleware) PermissionsMiddleware(permissions ...constants.Permission) echo.MiddlewareFunc { |
| 136 | + return func(next echo.HandlerFunc) echo.HandlerFunc { |
| 137 | + return func(c echo.Context) error { |
| 138 | + jwtData, ok := c.Get(constants.AuthCredentialContextKey.String()).(*security.JWTClaims) |
| 139 | + if !ok { |
| 140 | + return response.ErrorBuilder(app_errors.Forbidden(app_errors.ErrAccessDenied)).Send(c) |
| 141 | + } |
| 142 | + |
| 143 | + if !m.hasRequiredPermission(jwtData.Permissions, permissions) { |
| 144 | + return response.ErrorBuilder(app_errors.Forbidden(app_errors.ErrAccessDenied)).Send(c) |
| 145 | + } |
| 146 | + |
| 147 | + c.Set(constants.AuthCredentialContextKey.String(), jwtData) |
| 148 | + |
| 149 | + return next(c) |
| 150 | + } |
| 151 | + } |
| 152 | +} |
| 153 | + |
| 154 | +func (m *Middleware) hasRequiredPermission(userPermissions, requiredPermissions []constants.Permission) bool { |
| 155 | + requiredPermissionsMap := make(map[constants.Permission]bool) |
| 156 | + for _, permission := range requiredPermissions { |
| 157 | + requiredPermissionsMap[permission] = true |
| 158 | + } |
| 159 | + |
| 160 | + for _, permission := range userPermissions { |
| 161 | + if requiredPermissionsMap[permission] { |
| 162 | + return true |
| 163 | + } |
| 164 | + } |
| 165 | + |
| 166 | + return false |
| 167 | +} |
| 168 | +``` |
| 169 | +
|
| 170 | +### Assign Middleware to Endpoints |
| 171 | +```bash |
| 172 | +func MapUserRoutes(g echo.Group, h users.Handlers, mw *middlewares.Middleware) { |
| 173 | + users := g.Group("/users", mw.JWTMiddleware()) |
| 174 | + users.POST("", h.CreateUserHandler, mw.RolesMiddleware(constants.AdminUserRole), mw.PermissionsMiddleware(constants.UsersCreatePermission)) |
| 175 | +} |
| 176 | +``` |
| 177 | +
|
| 178 | +## Configuration ⚙️ |
| 179 | +```bash |
| 180 | +App: |
| 181 | + Name: "go-rbac" |
| 182 | + Version: "0.0.1" |
| 183 | + Scheme: "http" |
| 184 | + Host: "localhost:3002" |
| 185 | + Environment: local #local,development,staging,production |
| 186 | + |
| 187 | +Server: |
| 188 | + Port: "3002" |
| 189 | + Debug: true |
| 190 | + TimeZone: "Asia/Jakarta" |
| 191 | + |
| 192 | +Database: |
| 193 | + Host: "127.0.0.1" |
| 194 | + Port: "3306" |
| 195 | + DBName: "go_rbac" |
| 196 | + UserName: "root" |
| 197 | + Password: "pwd" |
| 198 | + Debug: true |
| 199 | + |
| 200 | +Security: |
| 201 | + JWT: |
| 202 | + Key: "95476ff7-c7b2-49d7-853e-322b6f983914" |
| 203 | + ExpiredInSecond: 3600 |
| 204 | +``` |
| 205 | +
|
| 206 | +## API Documentation 📑 |
| 207 | +
|
| 208 | +### Overview |
| 209 | +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. |
| 210 | +
|
| 211 | +### Explore Swagger Documentation |
| 212 | +For a detailed description of all the available API endpoints, request/response formats, and examples, explore our Swagger documentation at the following link: |
| 213 | +
|
| 214 | +- [Swagger Documentation](http://localhost:3002/swagger/index.html) |
| 215 | +
|
| 216 | +The Swagger documentation will provide detailed information on: |
| 217 | +- **Available Endpoints**: All API routes for managing users, roles, permissions, and access control. |
| 218 | +- **Request/Response Formats**: Detailed format for the expected input and output of each API endpoint. |
| 219 | +- **Authentication**: How to authenticate requests using JWT tokens. |
| 220 | +- **Role and Permission Validation**: How roles and permissions are validated for each endpoint. |
| 221 | +
|
| 222 | +## License 📄 |
| 223 | +This project is licensed under the [MIT License](LICENSE). See the LICENSE file for details. |
| 224 | +
|
| 225 | +## Contributing 🤝 |
| 226 | +Feel free to submit pull requests or open issues to improve this project. Contributions are always welcome! |
| 227 | +```bash |
| 228 | +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! |
| 229 | +``` |
| 230 | +
|
0 commit comments