using System.IdentityModel.Tokens.Jwt;
using System.Net;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
namespace server.Controllers;
///
/// 数据控制器
///
[ApiController]
[Route("api/[controller]")]
public class DataController : ControllerBase
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private readonly Database.UserManager _userManager = new();
// 固定的实验板IP,端口,MAC地址
private const string BOARD_IP = "169.254.109.0";
///
/// 获取本机IP地址(优先选择与实验板同网段的IP)
///
/// 本机IP地址
private IPAddress GetLocalIPAddress()
{
try
{
var boardIpSegments = BOARD_IP.Split('.').Take(3).ToArray();
// 优先选择与实验板IP前三段相同的IP
var sameSegmentIP = System.Net.NetworkInformation.NetworkInterface
.GetAllNetworkInterfaces()
.Where(nic => nic.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up
&& nic.NetworkInterfaceType != System.Net.NetworkInformation.NetworkInterfaceType.Loopback)
.SelectMany(nic => nic.GetIPProperties().UnicastAddresses)
.Where(addr => addr.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
.Select(addr => addr.Address)
.FirstOrDefault(addr =>
{
var segments = addr.ToString().Split('.');
return segments.Length == 4 &&
segments[0] == boardIpSegments[0] &&
segments[1] == boardIpSegments[1] &&
segments[2] == boardIpSegments[2];
});
if (sameSegmentIP != null)
return sameSegmentIP;
// 如果没有找到同网段的IP,返回第一个可用的IP
return System.Net.NetworkInformation.NetworkInterface
.GetAllNetworkInterfaces()
.Where(nic => nic.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up
&& nic.NetworkInterfaceType != System.Net.NetworkInformation.NetworkInterfaceType.Loopback)
.SelectMany(nic => nic.GetIPProperties().UnicastAddresses)
.Where(addr => addr.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
.Select(addr => addr.Address)
.FirstOrDefault() ?? IPAddress.Loopback;
}
catch (Exception ex)
{
logger.Error(ex, "获取本机IP地址失败");
return IPAddress.Loopback;
}
}
///
/// 用户登录,获取 JWT 令牌
///
/// 用户名
/// 用户密码
/// JWT 令牌字符串
[HttpPost("Login")]
[EnableCors("Users")]
[ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public IActionResult Login(string name, string password)
{
// 验证用户密码
var ret = _userManager.CheckUserPassword(name, password);
if (!ret.IsSuccessful) return StatusCode(StatusCodes.Status500InternalServerError, "数据库操作失败");
if (!ret.Value.HasValue) return BadRequest("用户名或密码错误");
var user = ret.Value.Value;
// 生成 JWT
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes("my secret key 1234567890my secret key 1234567890");
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, user.Name),
new Claim(ClaimTypes.Email, user.EMail),
new Claim(ClaimTypes.Role, user.Permission.ToString())
}),
Expires = DateTime.UtcNow.AddHours(1),
SigningCredentials = new SigningCredentials(
new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
Audience = "dlut.edu.cn",
Issuer = "dlut.edu.cn",
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var jwt = tokenHandler.WriteToken(token);
return Ok(jwt);
}
///
/// 测试用户认证,需携带有效 JWT
///
/// 认证成功信息
[Authorize]
[HttpGet("TestAuth")]
[EnableCors("Users")]
[ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public IActionResult TestAuth()
{
return Ok("认证成功!");
}
///
/// 测试管理员用户认证,需携带有效 JWT
///
/// 认证成功信息
[Authorize("Admin")]
[HttpGet("TestAdminAuth")]
[EnableCors("Users")]
[ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public IActionResult TestAdminAuth()
{
return Ok("认证成功!");
}
///
/// 获取当前用户信息
///
/// 用户信息,包括ID、用户名、邮箱和板卡ID
[Authorize]
[HttpGet("GetUserInfo")]
[EnableCors("Users")]
[ProducesResponseType(typeof(UserInfo), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public IActionResult GetUserInfo()
{
// Get User Name
var userName = User.Identity?.Name;
if (string.IsNullOrEmpty(userName))
return Unauthorized("未找到用户名信息");
// Get User Info
var ret = _userManager.GetUserByName(userName);
if (!ret.IsSuccessful)
return StatusCode(StatusCodes.Status500InternalServerError, "数据库操作失败");
if (!ret.Value.HasValue)
return BadRequest("用户不存在");
var user = ret.Value.Value;
return Ok(new UserInfo
{
ID = user.ID,
Name = user.Name,
EMail = user.EMail,
BoardID = user.BoardID,
BoardExpireTime = user.BoardExpireTime,
});
}
///
/// 注册新用户
///
/// 用户名(不超过255个字符)
/// 邮箱地址
/// 用户密码
/// 操作结果,成功返回 true,失败返回错误信息
[HttpPost("SignUpUser")]
[EnableCors("Users")]
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public IActionResult SignUpUser(string name, string email, string password)
{
// 验证输入参数
if (string.IsNullOrWhiteSpace(name))
return BadRequest("用户名不能为空");
if (name.Length > 255)
return BadRequest("用户名不能超过255个字符");
if (string.IsNullOrWhiteSpace(email))
return BadRequest("邮箱不能为空");
if (string.IsNullOrWhiteSpace(password))
return BadRequest("密码不能为空");
try
{
var ret = _userManager.AddUser(name, email, password);
return Ok(ret);
}
catch (Exception ex)
{
logger.Error(ex, "注册用户时发生异常");
return StatusCode(StatusCodes.Status500InternalServerError, "注册失败,请稍后重试");
}
}
///
/// 获取一个空闲的实验板(普通用户权限)
///
/// 绑定持续时间(小时),默认为1小时
[Authorize]
[HttpGet("GetAvailableBoard")]
[EnableCors("Users")]
[ProducesResponseType(typeof(Database.Board), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async ValueTask GetAvailableBoard(int durationHours = 1)
{
try
{
var userName = User.Identity?.Name;
if (string.IsNullOrEmpty(userName))
return Unauthorized("未找到用户名信息");
var userRet = _userManager.GetUserByName(userName);
if (!userRet.IsSuccessful || !userRet.Value.HasValue)
return BadRequest("用户不存在");
var user = userRet.Value.Value;
var expireTime = DateTime.UtcNow.AddHours(durationHours);
var boardOpt = _userManager.GetAvailableBoard(user.ID, expireTime);
if (!boardOpt.HasValue)
return NotFound("没有可用的实验板");
var boardInfo = boardOpt.Value;
if (!(await ArpClient.CheckOrAddAsync(boardInfo.IpAddr, boardInfo.MacAddr, GetLocalIPAddress().ToString())))
{
logger.Error($"无法配置ARP,实验板可能会无法连接");
}
return Ok(boardInfo);
}
catch (Exception ex)
{
logger.Error(ex, "获取空闲实验板时发生异常");
return StatusCode(StatusCodes.Status500InternalServerError, "获取失败,请稍后重试");
}
}
///
/// 解除当前用户绑定的实验板(普通用户权限)
///
[Authorize]
[HttpPost("UnbindBoard")]
[EnableCors("Users")]
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public IActionResult UnbindBoard()
{
try
{
var userName = User.Identity?.Name;
if (string.IsNullOrEmpty(userName))
return Unauthorized("未找到用户名信息");
var userRet = _userManager.GetUserByName(userName);
if (!userRet.IsSuccessful || !userRet.Value.HasValue)
return BadRequest("用户不存在");
var user = userRet.Value.Value;
var result = _userManager.UnbindUserFromBoard(user.ID);
return Ok(result > 0);
}
catch (Exception ex)
{
logger.Error(ex, "解除实验板绑定时发生异常");
return StatusCode(StatusCodes.Status500InternalServerError, "解除失败,请稍后重试");
}
}
///
/// 用户根据实验板ID获取实验板信息(普通用户权限)
///
[Authorize]
[HttpGet("GetBoardByID")]
[EnableCors("Users")]
[ProducesResponseType(typeof(Database.Board), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task GetBoardByID(Guid id)
{
try
{
var ret = _userManager.GetBoardByID(id);
if (!ret.IsSuccessful)
return StatusCode(StatusCodes.Status500InternalServerError, "数据库操作失败");
if (!ret.Value.HasValue)
return NotFound("未找到对应的实验板");
var boardInfo = ret.Value.Value;
if (!(await ArpClient.CheckOrAddAsync(boardInfo.IpAddr, boardInfo.MacAddr, GetLocalIPAddress().ToString())))
{
logger.Error($"无法配置ARP,实验板可能会无法连接");
}
return Ok(boardInfo);
}
catch (Exception ex)
{
logger.Error(ex, "获取实验板信息时发生异常");
return StatusCode(StatusCodes.Status500InternalServerError, "获取失败,请稍后重试");
}
}
///
/// 新增板子(管理员权限)
///
[Authorize("Admin")]
[HttpPost("AddBoard")]
[EnableCors("Users")]
[ProducesResponseType(typeof(Guid), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public IActionResult AddBoard(string name)
{
if (string.IsNullOrWhiteSpace(name))
return BadRequest("板子名称不能为空");
try
{
var ret = _userManager.AddBoard(name);
return Ok(ret);
}
catch (Exception ex)
{
logger.Error(ex, "新增板子时发生异常");
return StatusCode(StatusCodes.Status500InternalServerError, "新增失败,请稍后重试");
}
}
///
/// 删除板子(管理员权限)
///
[Authorize("Admin")]
[HttpDelete("DeleteBoard")]
[EnableCors("Users")]
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public IActionResult DeleteBoard(Guid id)
{
if (id == Guid.Empty)
return BadRequest("板子Guid不能为空");
try
{
var ret = _userManager.DeleteBoardByID(id);
return Ok(ret);
}
catch (Exception ex)
{
logger.Error(ex, "删除板子时发生异常");
return StatusCode(StatusCodes.Status500InternalServerError, "删除失败,请稍后重试");
}
}
///
/// 获取全部板子(管理员权限)
///
[Authorize("Admin")]
[HttpGet("GetAllBoards")]
[EnableCors("Users")]
[ProducesResponseType(typeof(Database.Board[]), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public IActionResult GetAllBoards()
{
try
{
var boards = _userManager.GetAllBoard();
return Ok(boards);
}
catch (Exception ex)
{
logger.Error(ex, "获取全部板子时发生异常");
return StatusCode(StatusCodes.Status500InternalServerError, "获取失败,请稍后重试");
}
}
///
/// 更新板卡名称(管理员权限)
///
[Authorize("Admin")]
[HttpPost("UpdateBoardName")]
[EnableCors("Users")]
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public IActionResult UpdateBoardName(Guid boardId, string newName)
{
if (boardId == Guid.Empty)
return BadRequest("板子Guid不能为空");
if (string.IsNullOrWhiteSpace(newName))
return BadRequest("新名称不能为空");
try
{
var result = _userManager.UpdateBoardName(boardId, newName);
return Ok(result);
}
catch (Exception ex)
{
logger.Error(ex, "更新板卡名称时发生异常");
return StatusCode(StatusCodes.Status500InternalServerError, "更新失败,请稍后重试");
}
}
///
/// 更新板卡状态(管理员权限)
///
[Authorize("Admin")]
[HttpPost("UpdateBoardStatus")]
[EnableCors("Users")]
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public IActionResult UpdateBoardStatus(Guid boardId, Database.BoardStatus newStatus)
{
if (boardId == Guid.Empty)
return BadRequest("板子Guid不能为空");
try
{
var result = _userManager.UpdateBoardStatus(boardId, newStatus);
return Ok(result);
}
catch (Exception ex)
{
logger.Error(ex, "更新板卡状态时发生异常");
return StatusCode(StatusCodes.Status500InternalServerError, "更新失败,请稍后重试");
}
}
[HttpPost("AddEmptyBoard")]
[EnableCors("Development")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public IActionResult AddEmptyBoard()
{
try
{
var boardId = _userManager.AddBoard("Test");
var result = _userManager.UpdateBoardStatus(boardId, Database.BoardStatus.Available);
return Ok();
}
catch (Exception ex)
{
logger.Error(ex, "新增板子时发生异常");
return StatusCode(StatusCodes.Status500InternalServerError, "新增失败,请稍后重试");
}
}
///
/// [TODO:description]
///
public class UserInfo
{
///
/// 用户的唯一标识符
///
public Guid ID { get; set; }
///
/// 用户的名称
///
public required string Name { get; set; }
///
/// 用户的电子邮箱
///
public required string EMail { get; set; }
///
/// 用户关联的板卡ID
///
public Guid BoardID { get; set; }
///
/// 用户绑定板子的过期时间
///
public DateTime? BoardExpireTime { get; set; }
}
}