id: security
Security & Authorization in SophiChain
ABP Framework Permission System
id: security
📖 Overview
SophiChain uses ABP's permission-based authorization system with hierarchical permissions and localization support.
id: security
🏗️ Permission System
1. Define Permissions
// Application.Contracts/Permissions/FinanceHubPermissionDefinitionProvider.cs
public class FinanceHubPermissionDefinitionProvider : PermissionDefinitionProvider
{
public override void Define(IPermissionDefinitionContext context)
{
var financeHubGroup = context.AddGroup(
FinanceHubPermissions.GroupName,
L("Permission:FinanceHub"));
// Admin root permission
var adminRoot = financeHubGroup.AddPermission(
FinanceHubPermissions.Admin.Default,
L("Permission:AdminRoot"));
// Admin.Wallets permissions
var adminWallets = adminRoot.AddChild(
FinanceHubPermissions.Admin.Wallets.Default,
L("Permission:Admin.Wallets"));
adminWallets.AddChild(
FinanceHubPermissions.Admin.Wallets.View,
L("Permission:Admin.Wallets.View"));
adminWallets.AddChild(
FinanceHubPermissions.Admin.Wallets.Create,
L("Permission:Admin.Wallets.Create"));
adminWallets.AddChild(
FinanceHubPermissions.Admin.Wallets.Update,
L("Permission:Admin.Wallets.Update"));
adminWallets.AddChild(
FinanceHubPermissions.Admin.Wallets.Delete,
L("Permission:Admin.Wallets.Delete"));
}
private static LocalizableString L(string name)
{
return LocalizableString.Create<FinanceHubResource>(name);
}
}
2. Permission Constants
// Application.Contracts/Permissions/FinanceHubPermissions.cs
public static class FinanceHubPermissions
{
public const string GroupName = "FinanceHub";
public static class Admin
{
public const string Default = GroupName + ".Admin";
public static class Wallets
{
public const string Default = Admin.Default + ".Wallets";
public const string View = Default + ".View";
public const string Create = Default + ".Create";
public const string Update = Default + ".Update";
public const string Delete = Default + ".Delete";
public const string Manage = Default + ".Manage";
public const string AdjustBalance = Default + ".AdjustBalance";
}
public static class Invoices
{
public const string Default = Admin.Default + ".Invoices";
public const string View = Default + ".View";
public const string Create = Default + ".Create";
public const string Update = Default + ".Update";
public const string Delete = Default + ".Delete";
}
}
public static class User
{
public const string Default = GroupName + ".User";
public static class Wallets
{
public const string Default = User.Default + ".Wallets";
public const string View = Default + ".View";
}
}
}
id: security
🎯 Authorization
Service-Level Authorization
// Class-level authorization
[Authorize(FinanceHubPermissions.Admin.Wallets.Default)]
public class AdminWalletAppService : FinanceHubAppService
{
// Method-level authorization
[Authorize(FinanceHubPermissions.Admin.Wallets.View)]
public virtual async Task<WalletDto> GetWalletAsync(Guid id)
{
var wallet = await _walletRepository.GetAsync(id);
return ObjectMapper.Map<Wallet, WalletDto>(wallet);
}
[Authorize(FinanceHubPermissions.Admin.Wallets.Create)]
public virtual async Task<WalletDto> CreateWalletAsync(CreateWalletDto input)
{
// Implementation
}
[Authorize(FinanceHubPermissions.Admin.Wallets.Delete)]
public virtual async Task DeleteWalletAsync(Guid id)
{
await _walletRepository.DeleteAsync(id);
}
}
Imperative Authorization
public class WalletService : DomainService // Inherits AuthorizationService
{
public async Task<bool> CanUserAccessWalletAsync(Guid walletId)
{
var result = await AuthorizationService.AuthorizeAsync(
FinanceHubPermissions.Admin.Wallets.View);
return result.Succeeded;
}
public async Task ProcessWalletAsync(Guid walletId)
{
await AuthorizationService.CheckAsync(
FinanceHubPermissions.Admin.Wallets.Manage);
// Process wallet
}
}
id: security
🔐 Authentication
JWT Token Authentication
ABP uses JWT tokens for authentication:
Login Request:
POST /api/account/login
Content-Type: application/json
{
"userNameOrEmailAddress": "admin",
"password": "1q2w3E*"
}
Response:
{
"accessToken": "eyJhbGciOiJIUzI1NiIs...",
"encryptedAccessToken": "...",
"expireInSeconds": 3600,
"userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
Using Token:
GET /api/financehub/wallets/{id}
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
id: security
👥 Users & Roles
Assigning Permissions to Roles
// In your seed data or admin UI
public class FinanceHubDataSeedContributor : IDataSeedContributor
{
public async Task SeedAsync(DataSeedContext context)
{
// Create admin role with permissions
var adminRole = new IdentityRole(
id: Guid.NewGuid(),
name: "FinanceAdmin",
tenantId: context.TenantId
);
await _roleRepository.InsertAsync(adminRole);
// Grant permissions to role
await _permissionManager.SetForRoleAsync(
adminRole.Name,
FinanceHubPermissions.Admin.Wallets.Default,
true
);
}
}
id: security
✅ Best Practices
Permission Design
- ✅ Use hierarchical permissions (Parent → Child)
- ✅ Define granular permissions (View, Create, Update, Delete)
- ✅ Use localized permission names
- ✅ Group related permissions
- ❌ Don't create too many permissions
- ❌ Don't hardcode permission strings
Authorization
- ✅ Use
[Authorize]attributes on services - ✅ Check permissions at service level, not UI
- ✅ Use method-level authorization for fine-grained control
- ✅ Use
IAuthorizationServicefor complex logic - ❌ Don't rely on UI-only authorization
- ❌ Don't check permissions in Domain layer
Security
- ✅ Always validate user input
- ✅ Use HTTPS in production
- ✅ Implement rate limiting
- ✅ Log security events
- ✅ Use strong passwords
- ❌ Don't expose sensitive data in APIs
- ❌ Don't log passwords or tokens
id: security
📖 References
id: security