0052725b88
- Created UserViewSheet component to display user details including username, full name, role, status, and timestamps. - Created RoleViewSheet component to display role details including name, level, status, creation date, and associated permissions. - Introduced permissions configuration in a new permissions.ts file, defining categories and permission codes for better management. - Implemented middleware for authentication, ensuring access control for protected routes.
3.9 KiB
3.9 KiB
Authentication & Authorization Layer
External Auth Service (AuthHex)
- Runs on
http://localhost:6703 - Owns credentials — this app never stores passwords
- Issues RS256-signed JWTs with claims:
sub,role_id,role_level,username,role_code
Directory Structure
Infra/
├── Auth/ External auth service integration
│ ├── AuthHexClient.cs HTTP proxy to AuthHex (/api/user)
│ ├── IAuthHexClient.cs
│ └── AuthHexResponse.cs Raw response shape from AuthHex
│
└── Authorization/ This app's permission enforcement
├── PermissionRequirement.cs ASP.NET Core requirement (wraps permission code string)
├── PermissionPolicyProvider.cs Builds policy dynamically for any "x.y" string
├── PermissionAuthorizationHandler.cs Evaluates requirement against DB
├── AuthorizationController.cs Exposes permission/scope check endpoints
├── CurrentUserService.cs Extracts typed claims from HttpContext.User
├── ICurrentUserService.cs
├── AuthorizationDTOs.cs
├── Permission/
│ ├── PermissionRepository.cs Queries RolePermissions + Permissions tables
│ ├── PermissionService.cs
│ ├── IPermissionRepository.cs
│ └── IPermissionService.cs
└── Scope/
├── ScopeRepository.cs Queries UserStoreScopes / UserRouteScopes / UserRegionScopes
├── ScopeAccessService.cs Resolves accessible stores via store → route → region hierarchy
├── IScopeRepository.cs
└── IScopeAccessService.cs
Login Flow
POST /api/auth/login
→ AuthController
→ AuthService.LoginAsync
→ AuthHexClient.CallAsync("loginUser", ...)
→ POST http://localhost:6703/api/user
← RS256-signed JWT returned to client
Request Flow
Incoming request with Authorization: Bearer <jwt>
│
▼
AuthMiddleware (Middleware/AuthMiddleware.cs)
- Reads Jwt:PublicKey from appsettings.json
- RSA.Create().FromXmlString(publicKeyXml)
- Validates JWT signature (RS256), issuer, audience, lifetime
- Sets HttpContext.User = principal (claims: sub, role_id, role_level, username)
│
▼
app.UseAuthorization()
- Global AuthorizeFilter: requires IsAuthenticated on every endpoint
- [Authorize("brand.view")] triggers PermissionPolicyProvider
→ builds AuthorizationPolicy with PermissionRequirement("brand.view")
→ PermissionAuthorizationHandler reads role_id claim
→ PermissionService.HasPermissionAsync(roleId, "brand.view")
→ DB: RolePermissions JOIN Permissions WHERE code = "brand.view"
│
▼
Controller
- ICurrentUserService.UserId / RoleId / RoleLevel extracted from HttpContext.User
- Scope guards: HasStoreScopeAsync / HasRouteScopeAsync / HasRegionScopeAsync
Scope System
Scope controls which records a user can access (not just which actions).
| Assignment table | Access granted to |
|---|---|
UserStoreScopes |
Specific stores directly |
UserRouteScopes |
All stores on that route |
UserRegionScopes |
All routes → all stores in that region |
ScopeAccessService.GetAccessibleStoreIdsAsync merges all three levels and deduplicates.
Pipeline Order (Program.cs)
app.UseCors();
app.UseMiddleware<AuthMiddleware>(); // 1. populate HttpContext.User
app.UseAuthorization(); // 2. evaluate [Authorize] attributes
UseAuthentication() is intentionally absent — JWT validation is done manually in AuthMiddleware, not via ASP.NET Core's built-in bearer scheme.
appsettings.json Keys
| Key | Purpose |
|---|---|
Jwt:PublicKey |
RSA XML public key from AuthHex (used by AuthMiddleware) |
Jwt:Issuer |
AuthHex |
Jwt:Audience |
AuthHexClient |
AuthHex:BaseUrl |
http://localhost:6703 |