Auth & Authorization
Estimated reading time: 4 minutes 预计阅读时间: 4 分钟Full Chinese version (with macro reference):
/guide/core/auth.
JWT config
Supported algorithms: HS256 / RS256 / ES256 / EdDSA. Production should prefer RS256 or EdDSA with key rotation.
Declarative macros
Wildcards: #[has_perm("system:*")] matches any system:foo:bar.
Bitmap RBAC
PermBitmapPlugin loads sys.menu (which carries both the perm string and a bit_position column) into memory at startup, building a two-way PermissionMap:
On login, the user's permission strings are encoded as a base64 bitmap and embedded in the JWT's pb claim — this is the key to keeping tokens short. 200+ permission codes shrink from a multi-KB string array to a few dozen base64 bytes.
On verification, validate_token decodes pb back into a string list and runs permission_matches for wildcard-aware exact matching (crates/summer-auth/src/session/manager.rs):
- Exact:
system:user:listmatchessystem:user:list - Super:
*matches everything - Trailing wildcard:
system:*matchessystem:user:list,system:role:add - Middle wildcard:
system:*:listmatchessystem:user:list,system:role:list - Segment count must match (unless ended in
*)
There is no "pure bit-AND" step — wildcard semantics can't be expressed by bitmaps alone. The bitmap exists to compress the token, not to speed up matching (string matching itself runs in hundreds of nanoseconds).
The source of truth for the bit positions is the sys.menu.bit_position column. Menus rarely change in production, so a startup-time full load works fine.
Sessions
crates/summer-auth/src/session/manager.rs stores session state as three independent string keys in Redis, not a single aggregated hash:
They are split because TTLs, lookup patterns, and lifecycles all differ. Detailed rationale: the deep-dive blog post.
max_devices = 5 triggers the earliest-logged-in device (by login_time) to be evicted when a 6th login happens — not the least recently active.
Force-out and refresh rotation
summerrs-admin has no "token blocklist". A single key, auth:deny:{login_id}, carries three meanings:
That's why the blog calls the deny key "a rotation trigger, not a blocker."
kick_device(Some(device)) calls logout(login_id, device) internally — kicking your own device and that device logging itself out have identical side effects: target device exits, all others go through one refresh cycle.
concurrent_login = false clears every existing device for the same user at login, so each user has exactly one active device at a time.
Source files
crates/summer-auth/src/lib.rscrates/summer-auth/src/middleware.rscrates/summer-auth/src/path_auth.rscrates/summer-auth/src/bitmap.rscrates/summer-admin-macros/src/auth_macro.rs
