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

264 lines
8.4 KiB
C#

using Fengling.AuthService.Data;
using Fengling.AuthService.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Security.Claims;
namespace Fengling.AuthService.Controllers;
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class OAuthClientsController : ControllerBase
{
private readonly ApplicationDbContext _context;
private readonly ILogger<OAuthClientsController> _logger;
public OAuthClientsController(
ApplicationDbContext context,
ILogger<OAuthClientsController> logger)
{
_context = context;
_logger = logger;
}
[HttpGet]
public async Task<ActionResult<object>> GetClients(
[FromQuery] int page = 1,
[FromQuery] int pageSize = 10,
[FromQuery] string? displayName = null,
[FromQuery] string? clientId = null,
[FromQuery] string? status = null)
{
var query = _context.OAuthApplications.AsQueryable();
if (!string.IsNullOrEmpty(displayName))
{
query = query.Where(c => c.DisplayName.Contains(displayName));
}
if (!string.IsNullOrEmpty(clientId))
{
query = query.Where(c => c.ClientId.Contains(clientId));
}
if (!string.IsNullOrEmpty(status))
{
query = query.Where(c => c.Status == status);
}
var totalCount = await query.CountAsync();
var clients = await query
.OrderByDescending(c => c.CreatedAt)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
var result = clients.Select(c => new
{
id = c.Id,
clientId = c.ClientId,
displayName = c.DisplayName,
redirectUris = c.RedirectUris,
postLogoutRedirectUris = c.PostLogoutRedirectUris,
scopes = c.Scopes,
grantTypes = c.GrantTypes,
clientType = c.ClientType,
consentType = c.ConsentType,
status = c.Status,
description = c.Description,
createdAt = c.CreatedAt,
});
return Ok(new
{
items = result,
totalCount,
page,
pageSize
});
}
[HttpGet("{id}")]
public async Task<ActionResult<OAuthApplication>> GetClient(long id)
{
var client = await _context.OAuthApplications.FindAsync(id);
if (client == null)
{
return NotFound();
}
return Ok(new
{
id = client.Id,
clientId = client.ClientId,
displayName = client.DisplayName,
redirectUris = client.RedirectUris,
postLogoutRedirectUris = client.PostLogoutRedirectUris,
scopes = client.Scopes,
grantTypes = client.GrantTypes,
clientType = client.ClientType,
consentType = client.ConsentType,
status = client.Status,
description = client.Description,
createdAt = client.CreatedAt,
});
}
[HttpGet("{id}/secret")]
public async Task<ActionResult<object>> GetClientSecret(long id)
{
var client = await _context.OAuthApplications.FindAsync(id);
if (client == null)
{
return NotFound();
}
return Ok(new
{
clientId = client.ClientId,
clientSecret = client.ClientSecret,
});
}
[HttpPost]
public async Task<ActionResult<OAuthApplication>> CreateClient(CreateOAuthClientDto dto)
{
if (await _context.OAuthApplications.AnyAsync(c => c.ClientId == dto.ClientId))
{
return BadRequest(new { message = "Client ID 已存在" });
}
var client = new OAuthApplication
{
ClientId = dto.ClientId,
ClientSecret = dto.ClientSecret,
DisplayName = dto.DisplayName,
RedirectUris = dto.RedirectUris,
PostLogoutRedirectUris = dto.PostLogoutRedirectUris,
Scopes = dto.Scopes,
GrantTypes = dto.GrantTypes,
ClientType = dto.ClientType,
ConsentType = dto.ConsentType,
Status = dto.Status,
Description = dto.Description,
CreatedAt = DateTime.UtcNow,
};
_context.OAuthApplications.Add(client);
await _context.SaveChangesAsync();
await CreateAuditLog("oauth", "create", "OAuthClient", client.Id, client.DisplayName, null, SerializeToJson(dto));
return CreatedAtAction(nameof(GetClient), new { id = client.Id }, client);
}
[HttpPut("{id}")]
public async Task<IActionResult> UpdateClient(long id, UpdateOAuthClientDto dto)
{
var client = await _context.OAuthApplications.FindAsync(id);
if (client == null)
{
return NotFound();
}
var oldValue = SerializeToJson(client);
client.DisplayName = dto.DisplayName;
client.RedirectUris = dto.RedirectUris;
client.PostLogoutRedirectUris = dto.PostLogoutRedirectUris;
client.Scopes = dto.Scopes;
client.GrantTypes = dto.GrantTypes;
client.ClientType = dto.ClientType;
client.ConsentType = dto.ConsentType;
client.Status = dto.Status;
client.Description = dto.Description;
await _context.SaveChangesAsync();
await CreateAuditLog("oauth", "update", "OAuthClient", client.Id, client.DisplayName, oldValue, SerializeToJson(client));
return NoContent();
}
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteClient(long id)
{
var client = await _context.OAuthApplications.FindAsync(id);
if (client == null)
{
return NotFound();
}
var oldValue = SerializeToJson(client);
_context.OAuthApplications.Remove(client);
await _context.SaveChangesAsync();
await CreateAuditLog("oauth", "delete", "OAuthClient", client.Id, client.DisplayName, 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();
}
private string SerializeToJson(object obj)
{
return System.Text.Json.JsonSerializer.Serialize(obj, new System.Text.Json.JsonSerializerOptions
{
WriteIndented = false
});
}
}
public class CreateOAuthClientDto
{
public string ClientId { get; set; } = string.Empty;
public string ClientSecret { get; set; } = string.Empty;
public string DisplayName { get; set; } = string.Empty;
public string[] RedirectUris { get; set; } = Array.Empty<string>();
public string[] PostLogoutRedirectUris { get; set; } = Array.Empty<string>();
public string[] Scopes { get; set; } = Array.Empty<string>();
public string[] GrantTypes { get; set; } = Array.Empty<string>();
public string ClientType { get; set; } = "confidential";
public string ConsentType { get; set; } = "implicit";
public string Status { get; set; } = "active";
public string? Description { get; set; }
}
public class UpdateOAuthClientDto
{
public string DisplayName { get; set; } = string.Empty;
public string[] RedirectUris { get; set; } = Array.Empty<string>();
public string[] PostLogoutRedirectUris { get; set; } = Array.Empty<string>();
public string[] Scopes { get; set; } = Array.Empty<string>();
public string[] GrantTypes { get; set; } = Array.Empty<string>();
public string ClientType { get; set; } = "confidential";
public string ConsentType { get; set; } = "implicit";
public string Status { get; set; } = "active";
public string? Description { get; set; }
}