271 lines
8.7 KiB
C#
271 lines
8.7 KiB
C#
using Fengling.AuthService.Models;
|
|
using Fengling.Console.Models.Dtos;
|
|
using Fengling.Console.Services;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using System.Security.Claims;
|
|
|
|
namespace Fengling.Console.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("api/[controller]")]
|
|
[Authorize]
|
|
public class OAuthClientsController : ControllerBase
|
|
{
|
|
private readonly IOAuthClientService _service;
|
|
private readonly ILogger<OAuthClientsController> _logger;
|
|
|
|
public OAuthClientsController(
|
|
IOAuthClientService service,
|
|
ILogger<OAuthClientsController> logger)
|
|
{
|
|
_service = service;
|
|
_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)
|
|
{
|
|
try
|
|
{
|
|
var (items, totalCount) = await _service.GetClientsAsync(page, pageSize, displayName, clientId, status);
|
|
|
|
var result = items.Select(c => new OAuthClientDto
|
|
{
|
|
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,
|
|
UpdatedAt = c.UpdatedAt,
|
|
});
|
|
|
|
return Ok(new
|
|
{
|
|
items = result,
|
|
totalCount,
|
|
page,
|
|
pageSize
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error getting clients");
|
|
return StatusCode(500, new { message = ex.Message });
|
|
}
|
|
}
|
|
|
|
[HttpGet("options")]
|
|
public ActionResult<object> GetClientOptions()
|
|
{
|
|
return Ok(_service.GetClientOptions());
|
|
}
|
|
|
|
[HttpGet("{id}")]
|
|
public async Task<ActionResult<OAuthClientDto>> GetClient(long id)
|
|
{
|
|
try
|
|
{
|
|
var client = await _service.GetClientAsync(id);
|
|
if (client == null)
|
|
{
|
|
return NotFound();
|
|
}
|
|
|
|
return Ok(new OAuthClientDto
|
|
{
|
|
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,
|
|
UpdatedAt = client.UpdatedAt,
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error getting client {Id}", id);
|
|
return StatusCode(500, new { message = ex.Message });
|
|
}
|
|
}
|
|
|
|
[HttpPost]
|
|
public async Task<ActionResult<OAuthClientDto>> CreateClient([FromBody] CreateOAuthClientDto dto)
|
|
{
|
|
try
|
|
{
|
|
var client = new OAuthApplication
|
|
{
|
|
ClientId = dto.ClientId,
|
|
ClientSecret = string.IsNullOrEmpty(dto.ClientSecret) ? GenerateSecureSecret() : dto.ClientSecret,
|
|
DisplayName = dto.DisplayName,
|
|
RedirectUris = dto.RedirectUris ?? Array.Empty<string>(),
|
|
PostLogoutRedirectUris = dto.PostLogoutRedirectUris ?? Array.Empty<string>(),
|
|
Scopes = dto.Scopes ?? new[] { "openid", "profile", "email", "api" },
|
|
GrantTypes = dto.GrantTypes ?? new[] { "authorization_code", "refresh_token" },
|
|
ClientType = dto.ClientType ?? "confidential",
|
|
ConsentType = dto.ConsentType ?? "explicit",
|
|
Status = dto.Status ?? "active",
|
|
Description = dto.Description,
|
|
CreatedAt = DateTime.UtcNow,
|
|
};
|
|
|
|
var created = await _service.CreateClientAsync(client);
|
|
|
|
return CreatedAtAction(nameof(GetClient), new { id = created.Id }, new OAuthClientDto
|
|
{
|
|
Id = created.Id,
|
|
ClientId = created.ClientId,
|
|
ClientSecret = created.ClientSecret,
|
|
DisplayName = created.DisplayName,
|
|
Status = created.Status,
|
|
CreatedAt = created.CreatedAt,
|
|
});
|
|
}
|
|
catch (InvalidOperationException ex)
|
|
{
|
|
return BadRequest(new { message = ex.Message });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error creating client");
|
|
return StatusCode(500, new { message = ex.Message });
|
|
}
|
|
}
|
|
|
|
[HttpPost("{id}/generate-secret")]
|
|
public async Task<ActionResult> GenerateSecret(long id)
|
|
{
|
|
try
|
|
{
|
|
var client = await _service.GenerateSecretAsync(id);
|
|
return Ok(new
|
|
{
|
|
clientId = client.ClientId,
|
|
clientSecret = client.ClientSecret,
|
|
message = "新密钥已生成,请妥善保管,刷新后将无法再次查看"
|
|
});
|
|
}
|
|
catch (KeyNotFoundException ex)
|
|
{
|
|
return NotFound(new { message = ex.Message });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error generating secret for client {Id}", id);
|
|
return StatusCode(500, new { message = ex.Message });
|
|
}
|
|
}
|
|
|
|
[HttpPost("{id}/toggle-status")]
|
|
public async Task<ActionResult> ToggleStatus(long id)
|
|
{
|
|
try
|
|
{
|
|
var client = await _service.ToggleStatusAsync(id);
|
|
return Ok(new
|
|
{
|
|
clientId = client.ClientId,
|
|
newStatus = client.Status,
|
|
message = $"客户端状态已更改为 {client.Status}"
|
|
});
|
|
}
|
|
catch (KeyNotFoundException ex)
|
|
{
|
|
return NotFound(new { message = ex.Message });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error toggling status for client {Id}", id);
|
|
return StatusCode(500, new { message = ex.Message });
|
|
}
|
|
}
|
|
|
|
[HttpPut("{id}")]
|
|
public async Task<IActionResult> UpdateClient(long id, [FromBody] UpdateOAuthClientDto dto)
|
|
{
|
|
try
|
|
{
|
|
var client = await _service.GetClientAsync(id);
|
|
if (client == null)
|
|
{
|
|
return NotFound();
|
|
}
|
|
|
|
var updated = new OAuthApplication
|
|
{
|
|
Id = id,
|
|
ClientId = client.ClientId,
|
|
ClientSecret = client.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 = client.CreatedAt,
|
|
};
|
|
|
|
await _service.UpdateClientAsync(id, updated);
|
|
return NoContent();
|
|
}
|
|
catch (KeyNotFoundException ex)
|
|
{
|
|
return NotFound(new { message = ex.Message });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error updating client {Id}", id);
|
|
return StatusCode(500, new { message = ex.Message });
|
|
}
|
|
}
|
|
|
|
[HttpDelete("{id}")]
|
|
public async Task<IActionResult> DeleteClient(long id)
|
|
{
|
|
try
|
|
{
|
|
await _service.DeleteClientAsync(id);
|
|
return NoContent();
|
|
}
|
|
catch (KeyNotFoundException ex)
|
|
{
|
|
return NotFound(new { message = ex.Message });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error deleting client {Id}", id);
|
|
return StatusCode(500, new { message = ex.Message });
|
|
}
|
|
}
|
|
|
|
private static string GenerateSecureSecret(int length = 32)
|
|
{
|
|
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
var bytes = System.Security.Cryptography.RandomNumberGenerator.GetBytes(length);
|
|
return new string(bytes.Select(b => chars[b % chars.Length]).ToArray());
|
|
}
|
|
}
|