基于Keycloak设计多服务SSO及多餐厅多角色用户访问系统的最佳实践咨询
Great question—this multi-tenant, role-per-context scenario is super common in SaaS apps like restaurant management tools, and Keycloak absolutely has the tools to pull this off cleanly if you structure it right. Let’s break down the best practice that’s easy to build and maintain, tailored exactly to your restaurant use case.
Here’s the thing about Keycloak: it’s powerful, but all those options (scopes, policies, groups) can feel overwhelming at first. The key is to map your real-world entities directly to Keycloak’s features without overcomplicating it:
- Restaurants = Keycloak Groups: Each restaurant gets its own realm group (e.g.,
Best Pizza (ID:1),Not the Best Pizza (ID:2)). - Roles = Composite Permission Sets: Create reusable realm-level roles (like
Owner,Employee) that bundle granular permissions (e.g.,view-order,edit-order). - User-Role Assignment = Group-Specific: Assign roles to users within specific restaurant groups so the same user can have different roles across different restaurants.
1. Build Granular Permissions & Composite Roles
First, define the smallest unit of permission, then bundle them into roles that match your user types:
- In your Keycloak realm, go to Roles > Realm Roles and create granular permission roles:
view-orderedit-orderdelete-order
- Create composite roles that represent your user types, combining the permissions they need:
Owner: Addview-order,edit-order,delete-orderas composite rolesEmployee: Addview-orderas a composite role (you can adjust this later for specific restaurants)Cashier: Addview-order,edit-order(for cases like Jane Doe in your example)
2. Create Restaurant Groups & Assign Group-Specific Roles
Next, model each restaurant as a group, then assign roles to users within those groups:
- Go to Groups in your realm, create a group for each restaurant (use the restaurant ID in the name for clarity, e.g.,
Best Pizza (ID:1)). - For each user:
- Navigate to their profile → Groups → Select the restaurant group → Click Assign Role
- Choose the appropriate role (e.g., assign
Ownerto John Doe inBest Pizza (ID:1),Employeeto Mark in the same group) - Repeat for other restaurants (e.g., assign
Ownerto Mark inNot the Best Pizza (ID:2)).
This ensures the user’s role is tied directly to the restaurant context—no more confusion about which role applies where.
3. Configure Client Scopes to Expose Context in Tokens
To make this data usable in your services, you need to include group and role context in the access token. Here’s how:
- Go to Client Scopes → Create a custom scope named
restaurant-context. - Add two mappers to this scope:
- Group Membership Mapper: Set the claim name to
restaurants, configure it to return group IDs/names (whichever your app uses to identify restaurants). Disable "Full group path" since you don’t need hierarchy. - Group Role Mapper: Set the claim name to
restaurant_roles, configure it to return roles per group. This will give you a JSON object like:"restaurant_roles": { "Best Pizza (ID:1)": ["Employee"], "Not the Best Pizza (ID:2)": ["Owner"] }
- Group Membership Mapper: Set the claim name to
- Attach this custom scope to all your service clients so every login token includes this context.
4. Enforce Permissions in Your Services
Once the token has the restaurant context, your services can validate permissions without calling Keycloak every time. Here’s a quick example in Python:
def has_required_permission(token, restaurant_id, required_permission): # Map roles to their allowed permissions (store this in your service config) role_permissions = { "Owner": ["view-order", "edit-order", "delete-order"], "Employee": ["view-order"], "Cashier": ["view-order", "edit-order"] } # Get the user's roles for the target restaurant restaurant_roles = token.get("restaurant_roles", {}).get(restaurant_id, []) # Check if any role grants the required permission for role in restaurant_roles: if required_permission in role_permissions.get(role, []): return True return False
5. Enable SSO Across Services
SSO works out of the box here—just configure all your services to use the same Keycloak realm. Users log in once, get a token valid for all services, and each service uses the token’s claims to enforce permissions. No extra setup needed!
- Simple to Scale: Adding a new restaurant is just creating a group and assigning roles—no complex policy changes.
- Clear Separation: Permissions are tied to roles, roles are tied to restaurant groups, so you never mix up which user has access where.
- Low Overhead: All context lives in the token, so your services don’t need to make repeated calls to Keycloak’s API.
- Flexible: If you need to adjust permissions for a specific restaurant (e.g., let an Employee edit orders), just add the
edit-orderrole to their group assignment.
You might consider using a separate realm for each restaurant, but that’s overkill here. It adds complexity for user management (you’d need federation to share users across realms) and makes SSO harder to implement. Groups are the simpler, more maintainable choice for your scenario.
内容的提问来源于stack exchange,提问作者Pedro Rocha

