fengling-auth-service/Controllers/TenantsController.cs
2026-02-03 15:30:12 +08:00

345 lines
11 KiB
C#

using Fengling.AuthService.Data;
using Fengling.AuthService.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Security.Claims;
using System.Text.Json;
namespace Fengling.AuthService.Controllers;
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class TenantsController : ControllerBase
{
private readonly ApplicationDbContext _context;
private readonly UserManager<ApplicationUser> _userManager;
private readonly ILogger<TenantsController> _logger;
public TenantsController(
ApplicationDbContext context,
UserManager<ApplicationUser> userManager,
ILogger<TenantsController> logger)
{
_context = context;
_userManager = userManager;
_logger = logger;
}
[HttpGet]
public async Task<ActionResult<object>> GetTenants(
[FromQuery] int page = 1,
[FromQuery] int pageSize = 10,
[FromQuery] string? name = null,
[FromQuery] string? tenantId = null,
[FromQuery] string? status = null)
{
var query = _context.Tenants.AsQueryable();
if (!string.IsNullOrEmpty(name))
{
query = query.Where(t => t.Name.Contains(name));
}
if (!string.IsNullOrEmpty(tenantId))
{
query = query.Where(t => t.TenantId.Contains(tenantId));
}
if (!string.IsNullOrEmpty(status))
{
query = query.Where(t => t.Status == status);
}
var totalCount = await query.CountAsync();
var tenants = await query
.OrderByDescending(t => t.CreatedAt)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
var result = new List<object>();
foreach (var tenant in tenants)
{
var userCount = await _context.Users.CountAsync(u => u.TenantId == tenant.Id && !u.IsDeleted);
result.Add(new
{
id = tenant.Id,
tenantId = tenant.TenantId,
name = tenant.Name,
contactName = tenant.ContactName,
contactEmail = tenant.ContactEmail,
contactPhone = tenant.ContactPhone,
maxUsers = tenant.MaxUsers,
userCount,
status = tenant.Status,
expiresAt = tenant.ExpiresAt,
description = tenant.Description,
createdAt = tenant.CreatedAt,
});
}
return Ok(new
{
items = result,
totalCount,
page,
pageSize
});
}
[HttpGet("{id}")]
public async Task<ActionResult<Tenant>> GetTenant(long id)
{
var tenant = await _context.Tenants.FindAsync(id);
if (tenant == null)
{
return NotFound();
}
return Ok(new
{
id = tenant.Id,
tenantId = tenant.TenantId,
name = tenant.Name,
contactName = tenant.ContactName,
contactEmail = tenant.ContactEmail,
contactPhone = tenant.ContactPhone,
maxUsers = tenant.MaxUsers,
status = tenant.Status,
expiresAt = tenant.ExpiresAt,
description = tenant.Description,
createdAt = tenant.CreatedAt,
updatedAt = tenant.UpdatedAt,
});
}
[HttpGet("{tenantId}/users")]
public async Task<ActionResult<List<object>>> GetTenantUsers(string tenantId)
{
var tenant = await _context.Tenants.FirstOrDefaultAsync(t => t.TenantId == tenantId);
if (tenant == null)
{
return NotFound();
}
var users = await _context.Users
.Where(u => u.TenantId == tenant.Id && !u.IsDeleted)
.ToListAsync();
var result = users.Select(async u => new
{
id = u.Id,
userName = u.UserName,
email = u.Email,
realName = u.RealName,
tenantId = u.TenantId,
roles = await _userManager.GetRolesAsync(u),
isActive = !u.LockoutEnabled || u.LockoutEnd == null || u.LockoutEnd < DateTimeOffset.UtcNow,
createdAt = u.CreatedTime,
});
return Ok(await Task.WhenAll(result));
}
[HttpGet("{tenantId}/roles")]
public async Task<ActionResult<List<object>>> GetTenantRoles(string tenantId)
{
var tenant = await _context.Tenants.FirstOrDefaultAsync(t => t.TenantId == tenantId);
if (tenant == null)
{
return NotFound();
}
var roles = await _context.Roles
.Where(r => r.TenantId == tenant.Id)
.ToListAsync();
var result = roles.Select(r => new
{
id = r.Id,
name = r.Name,
displayName = r.DisplayName,
});
return Ok(result);
}
[HttpGet("{tenantId}/settings")]
public async Task<ActionResult<TenantSettings>> GetTenantSettings(string tenantId)
{
var tenant = await _context.Tenants.FirstOrDefaultAsync(t => t.TenantId == tenantId);
if (tenant == null)
{
return NotFound();
}
var settings = new TenantSettings
{
AllowRegistration = false,
AllowedEmailDomains = "",
DefaultRoleId = null,
PasswordPolicy = new List<string> { "requireNumber", "requireLowercase" },
MinPasswordLength = 8,
SessionTimeout = 120,
};
return Ok(settings);
}
[HttpPut("{tenantId}/settings")]
public async Task<IActionResult> UpdateTenantSettings(string tenantId, TenantSettings settings)
{
var tenant = await _context.Tenants.FirstOrDefaultAsync(t => t.TenantId == tenantId);
if (tenant == null)
{
return NotFound();
}
await CreateAuditLog("tenant", "update", "TenantSettings", tenant.Id, tenant.TenantId, null, JsonSerializer.Serialize(settings));
return NoContent();
}
[HttpPost]
public async Task<ActionResult<Tenant>> CreateTenant(CreateTenantDto dto)
{
var tenant = new Tenant
{
TenantId = dto.TenantId,
Name = dto.Name,
ContactName = dto.ContactName,
ContactEmail = dto.ContactEmail,
ContactPhone = dto.ContactPhone,
MaxUsers = dto.MaxUsers,
Description = dto.Description,
Status = dto.Status,
ExpiresAt = dto.ExpiresAt,
CreatedAt = DateTime.UtcNow,
};
_context.Tenants.Add(tenant);
await _context.SaveChangesAsync();
await CreateAuditLog("tenant", "create", "Tenant", tenant.Id, tenant.TenantId, null, JsonSerializer.Serialize(dto));
return CreatedAtAction(nameof(GetTenant), new { id = tenant.Id }, tenant);
}
[HttpPut("{id}")]
public async Task<IActionResult> UpdateTenant(long id, UpdateTenantDto dto)
{
var tenant = await _context.Tenants.FindAsync(id);
if (tenant == null)
{
return NotFound();
}
var oldValue = JsonSerializer.Serialize(tenant);
tenant.Name = dto.Name;
tenant.ContactName = dto.ContactName;
tenant.ContactEmail = dto.ContactEmail;
tenant.ContactPhone = dto.ContactPhone;
tenant.MaxUsers = dto.MaxUsers;
tenant.Description = dto.Description;
tenant.Status = dto.Status;
tenant.ExpiresAt = dto.ExpiresAt;
tenant.UpdatedAt = DateTime.UtcNow;
await _context.SaveChangesAsync();
await CreateAuditLog("tenant", "update", "Tenant", tenant.Id, tenant.TenantId, oldValue, JsonSerializer.Serialize(tenant));
return NoContent();
}
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTenant(long id)
{
var tenant = await _context.Tenants.FindAsync(id);
if (tenant == null)
{
return NotFound();
}
var oldValue = JsonSerializer.Serialize(tenant);
var users = await _context.Users.Where(u => u.TenantId == tenant.Id).ToListAsync();
foreach (var user in users)
{
user.IsDeleted = true;
user.UpdatedTime = DateTime.UtcNow;
}
tenant.IsDeleted = true;
await _context.SaveChangesAsync();
await CreateAuditLog("tenant", "delete", "Tenant", tenant.Id, tenant.TenantId, oldValue);
return NoContent();
}
private async Task CreateAuditLog(string operation, string action, string targetType, long? targetId, string? targetName, string? oldValue = null, string? newValue = null)
{
var userName = User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.Identity?.Name ?? "system";
var tenantId = User.FindFirstValue("TenantId");
var log = new AuditLog
{
Operator = userName,
TenantId = tenantId,
Operation = operation,
Action = action,
TargetType = targetType,
TargetId = targetId,
TargetName = targetName,
IpAddress = HttpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown",
Status = "success",
OldValue = oldValue,
NewValue = newValue,
};
_context.AuditLogs.Add(log);
await _context.SaveChangesAsync();
}
}
public class CreateTenantDto
{
public string TenantId { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string ContactName { get; set; } = string.Empty;
public string ContactEmail { get; set; } = string.Empty;
public string? ContactPhone { get; set; }
public int? MaxUsers { get; set; }
public string? Description { get; set; }
public string Status { get; set; } = "active";
public DateTime? ExpiresAt { get; set; }
}
public class UpdateTenantDto
{
public string Name { get; set; } = string.Empty;
public string ContactName { get; set; } = string.Empty;
public string ContactEmail { get; set; } = string.Empty;
public string? ContactPhone { get; set; }
public int? MaxUsers { get; set; }
public string? Description { get; set; }
public string Status { get; set; } = "active";
public DateTime? ExpiresAt { get; set; }
}
public class TenantSettings
{
public bool AllowRegistration { get; set; }
public string AllowedEmailDomains { get; set; } = string.Empty;
public long? DefaultRoleId { get; set; }
public List<string> PasswordPolicy { get; set; } = new();
public int MinPasswordLength { get; set; } = 8;
public int SessionTimeout { get; set; } = 120;
}