controller-roles
Role-based access control with RoleHandler
When & Why to Use This Skill
This Claude skill provides a robust framework for implementing Role-Based Access Control (RBAC) in Go-based web applications. By utilizing the RoleHandler, developers can efficiently map user roles to specific handler functions, manage hierarchical permissions, and automate session context injection, ensuring secure and scalable API endpoint management.
Use Cases
- Securing administrative dashboards by restricting destructive actions (Create, Update, Delete) to users with ROLE_ADMIN privileges.
- Implementing read-only access for auditors or support staff using hierarchical fallbacks, allowing them to view data without modification rights.
- Providing differentiated API responses on the same route, where administrators receive full data sets while standard users receive limited, public-facing information.
- Streamlining backend development by automatically extracting session data and user roles from requests to reduce boilerplate security code.
| name | controller-roles |
|---|---|
| description | Role-based access control with RoleHandler |
Role-Based Access Control
The helpers.RoleHandler function provides role-based access control by mapping roles to specific handler functions.
Basic Usage
helpers.RoleHandler(helpers.RoleHandlerMap{
constants.ROLE_READ_ADMIN: helpers.StandardRequestWrapper(adminGet),
constants.ROLE_ADMIN: helpers.StandardRequestWrapper(adminCreate),
})
Role Hierarchy
Roles are defined as integer constants in descending order of privilege:
| Role | Value | Description |
|---|---|---|
ROLE_ADMIN |
100 | Full system administrator access |
ROLE_READ_ADMIN |
90 | Read-only administrator access |
ROLE_ANY_AUTHORIZED |
0 | Any authenticated user |
ROLE_UNAUTHORIZED |
-1 | Unauthenticated requests |
How RoleHandler Works
- Extracts session from request headers/cookies
- Looks up user's role from the database
- Finds highest-privilege handler the user can access
- Falls back to lower privilege handlers if exact role match isn't found
- Returns 401 Unauthorized if no suitable handler is found
Fallback Behavior
If a user's role doesn't exactly match a handler, the system checks lower-privilege handlers:
helpers.RoleHandler(helpers.RoleHandlerMap{
constants.ROLE_READ_ADMIN: helpers.StandardRequestWrapper(adminGet),
constants.ROLE_ANY_AUTHORIZED: helpers.StandardRequestWrapper(authGet),
})
Examples:
- User with
ROLE_ADMIN(100) → UsesROLE_READ_ADMINhandler (fallback) - User with
ROLE_READ_ADMIN(90) → UsesROLE_READ_ADMINhandler (exact match) - User with
ROLE_ANY_AUTHORIZED(0) → UsesROLE_ANY_AUTHORIZEDhandler (exact match) - Unauthenticated user → Returns 401 Unauthorized
Session Context
The RoleHandler automatically injects the session into the request context, making it available via:
userSession := helpers.GetReqSession(req)
Session Fields:
type Session struct {
User coremodel.Model // thin wrapper over session data if you only need the users ID, i.e. sessionObj.User.ID(), or used to save data so we can track who saved it.
LoadedUser any // fully loaded user from the database, dont access directly, use the helper.GetLoadedUser(req)
}
Common Role Patterns
Admin-Only Endpoints
Full admin access required:
r.Post("/", helpers.RoleHandler(helpers.RoleHandlerMap{
constants.ROLE_ADMIN: helpers.StandardRequestWrapper(adminCreate),
}))
r.Put("/{id}", helpers.RoleHandler(helpers.RoleHandlerMap{
constants.ROLE_ADMIN: helpers.StandardRequestWrapper(adminUpdate),
}))
r.Delete("/{id}", helpers.RoleHandler(helpers.RoleHandlerMap{
constants.ROLE_ADMIN: helpers.StandardRequestWrapper(adminDelete),
}))
Read-Only Admin Access
Both full admins and read-only admins can access:
r.Get("/", helpers.RoleHandler(helpers.RoleHandlerMap{
constants.ROLE_READ_ADMIN: helpers.StandardRequestWrapper(adminIndex),
}))
r.Get("/{id}", helpers.RoleHandler(helpers.RoleHandlerMap{
constants.ROLE_READ_ADMIN: helpers.StandardRequestWrapper(adminGet),
}))
r.Get("/count", helpers.RoleHandler(helpers.RoleHandlerMap{
constants.ROLE_READ_ADMIN: helpers.StandardRequestWrapper(adminCount),
}))
Authenticated User Endpoints
Any authenticated user can access:
r.Get("/", helpers.RoleHandler(helpers.RoleHandlerMap{
constants.ROLE_ANY_AUTHORIZED: helpers.StandardPublicRequestWrapper(authIndex),
}))
r.Get("/{id}", helpers.RoleHandler(helpers.RoleHandlerMap{
constants.ROLE_ANY_AUTHORIZED: helpers.StandardPublicRequestWrapper(authGet),
}))
Mixed Role Handlers
Different handlers for different roles on the same route:
r.Get("/{id}", helpers.RoleHandler(helpers.RoleHandlerMap{
constants.ROLE_ADMIN: helpers.StandardRequestWrapper(adminGetFull),
constants.ROLE_ANY_AUTHORIZED: helpers.StandardPublicRequestWrapper(authGetLimited),
}))
Example:
- Admin users → Get full details via
adminGetFull - Regular users → Get limited details via
authGetLimited
Related Skills
- controller-handlers - Writing handler functions
- controller-generation - Code generation