提交
This commit is contained in:
40
Hotfix/Api/Controllers/AuthController.cs
Normal file
40
Hotfix/Api/Controllers/AuthController.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System.Threading;
|
||||
using Fantasy;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Network.HTTP;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace NBF;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[ServiceFilter(typeof(SceneContextFilter))]
|
||||
public class AuthController : ControllerBase
|
||||
{
|
||||
private readonly Scene _scene;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数依赖注入
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
public AuthController(Scene scene)
|
||||
{
|
||||
_scene = scene;
|
||||
}
|
||||
|
||||
[HttpGet("login")]
|
||||
public async FTask<IActionResult> Login()
|
||||
{
|
||||
await DingTalkHelper.SendCAPTCHA("123456");
|
||||
await FTask.CompletedTask;
|
||||
return Ok($"Hello from the Fantasy controller! _scene.SceneType:{_scene.SceneType} _scene.SceneType:{_scene.SceneConfigId}");
|
||||
}
|
||||
|
||||
[HttpGet("code")]
|
||||
public async FTask<IActionResult> SendCode()
|
||||
{
|
||||
await DingTalkHelper.SendCAPTCHA("123456");
|
||||
await FTask.CompletedTask;
|
||||
return Ok($"Hello from the Fantasy controller! _scene.SceneType:{_scene.SceneType} _scene.SceneType:{_scene.SceneConfigId}");
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ namespace NBF
|
||||
// 5. 自定义响应头
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
context.Response.Headers.Add("X-Game-Server", "Fantasy");
|
||||
context.Response.Headers.Add("X-Game-Server", "NBF");
|
||||
context.Response.Headers.Add("X-Server-Version", "1.0.0");
|
||||
await next.Invoke();
|
||||
});
|
||||
@@ -7,6 +7,7 @@ using Microsoft.IdentityModel.Tokens;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Fantasy;
|
||||
|
||||
namespace NBF;
|
||||
|
||||
@@ -27,8 +28,8 @@ public class GameHttpServicesHandler : AsyncEventSystem<OnConfigureHttpServices>
|
||||
// 2. 添加全局过滤器
|
||||
self.MvcBuilder.AddMvcOptions(options =>
|
||||
{
|
||||
options.Filters.Add<GameExceptionFilter>();
|
||||
options.Filters.Add<ModelValidationFilter>();
|
||||
// options.Filters.Add<GameExceptionFilter>();
|
||||
// options.Filters.Add<ModelValidationFilter>();
|
||||
});
|
||||
|
||||
// 3. 配置 JWT 认证
|
||||
@@ -76,11 +77,11 @@ public class GameHttpServicesHandler : AsyncEventSystem<OnConfigureHttpServices>
|
||||
});
|
||||
});
|
||||
|
||||
// 6. 注册游戏服务
|
||||
self.Builder.Services.AddSingleton<IPlayerService, PlayerService>();
|
||||
self.Builder.Services.AddSingleton<IGuildService, GuildService>();
|
||||
self.Builder.Services.AddScoped<IAuthService, AuthService>();
|
||||
self.Builder.Services.AddScoped<IGameRepository, GameRepository>();
|
||||
// // 6. 注册游戏服务
|
||||
// self.Builder.Services.AddSingleton<IPlayerService, PlayerService>();
|
||||
// self.Builder.Services.AddSingleton<IGuildService, GuildService>();
|
||||
// self.Builder.Services.AddScoped<IAuthService, AuthService>();
|
||||
// self.Builder.Services.AddScoped<IGameRepository, GameRepository>();
|
||||
|
||||
Log.Info($"[HTTP] 游戏服务配置完成: Scene {self.Scene.SceneConfigId}");
|
||||
|
||||
63
Hotfix/Api/Helper/DingTalkHelper.cs
Normal file
63
Hotfix/Api/Helper/DingTalkHelper.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System.Text;
|
||||
using Fantasy;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace NBF;
|
||||
|
||||
public static class DingTalkHelper
|
||||
{
|
||||
private static readonly HttpClient _httpClient = new HttpClient();
|
||||
|
||||
public static async Task SendCAPTCHA(string code)
|
||||
{
|
||||
DingTalkMarkdownData dingTalkTestData = new DingTalkMarkdownData
|
||||
{
|
||||
markdown = new DingTalkMarkdownItem
|
||||
{
|
||||
title = "NB验证码",
|
||||
text = $"验证码:{code}"
|
||||
}
|
||||
};
|
||||
await SendMessageAsync("23457f9c93ac0ae909e1cbf8bcfeb7e0573968ac2d4c4b2c3a961b2f0c9247cb", dingTalkTestData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通用消息发送方法
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="message">消息对象</param>
|
||||
/// <returns></returns>
|
||||
private static async Task<bool> SendMessageAsync(string token, DingTalkMarkdownData message)
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(message);
|
||||
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
||||
var response =
|
||||
await _httpClient.PostAsync($"https://oapi.dingtalk.com/robot/send?access_token={token}", content);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
Log.Info($"钉钉={responseContent}");
|
||||
// 检查响应是否成功
|
||||
return response.IsSuccessStatusCode;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"发送飞书消息失败: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class DingTalkMarkdownData
|
||||
{
|
||||
public string msgtype { get; set; } = "markdown";
|
||||
public DingTalkMarkdownItem markdown { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class DingTalkMarkdownItem
|
||||
{
|
||||
public string title { get; set; }
|
||||
public string text { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
using Fantasy;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace NBF.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class PlayerController : ControllerBase
|
||||
{
|
||||
private readonly Scene _scene;
|
||||
private readonly IPlayerService _playerService;
|
||||
|
||||
public PlayerController(Scene scene, IPlayerService playerService)
|
||||
{
|
||||
_scene = scene;
|
||||
_playerService = playerService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取玩家信息(需要认证)
|
||||
/// </summary>
|
||||
[HttpGet("{playerId}")]
|
||||
[Authorize(Policy = "Player")]
|
||||
public async Task<IActionResult> GetPlayer(long playerId)
|
||||
{
|
||||
var player = await _playerService.GetPlayerAsync(playerId);
|
||||
if (player == null)
|
||||
{
|
||||
return NotFound(new { error = "Player not found" });
|
||||
}
|
||||
|
||||
return Ok(new
|
||||
{
|
||||
playerId = player.Id,
|
||||
name = player.Name,
|
||||
level = player.Level,
|
||||
exp = player.Exp
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 登录接口(无需认证)
|
||||
/// </summary>
|
||||
[HttpPost("login")]
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> Login([FromBody] LoginRequest request)
|
||||
{
|
||||
var (success, token, playerId) = await _playerService.LoginAsync(
|
||||
request.Username, request.Password);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
return Unauthorized(new { error = "Invalid credentials" });
|
||||
}
|
||||
|
||||
return Ok(new
|
||||
{
|
||||
token = token,
|
||||
playerId = playerId,
|
||||
expiresIn = 3600
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 管理员接口(需要 Admin 角色)
|
||||
/// </summary>
|
||||
[HttpPost("ban/{playerId}")]
|
||||
[Authorize(Policy = "Admin")]
|
||||
public async Task<IActionResult> BanPlayer(long playerId, [FromBody] BanRequest request)
|
||||
{
|
||||
await _playerService.BanPlayerAsync(playerId, request.Reason, request.Duration);
|
||||
|
||||
return Ok(new { message = "Player banned successfully" });
|
||||
}
|
||||
}
|
||||
|
||||
public class LoginRequest
|
||||
{
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
}
|
||||
|
||||
public class BanRequest
|
||||
{
|
||||
public string Reason { get; set; }
|
||||
public int Duration { get; set; } // 分钟
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace NBF;
|
||||
|
||||
public class PlayerService : IPlayerService
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
using System.Threading;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Entitas;
|
||||
using Fantasy.Network.HTTP;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Fantasy;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[ServiceFilter(typeof(SceneContextFilter))]
|
||||
public class HelloController : ControllerBase
|
||||
{
|
||||
private readonly Scene _scene;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数依赖注入
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
public HelloController(Scene scene)
|
||||
{
|
||||
_scene = scene;
|
||||
}
|
||||
|
||||
[HttpGet("greet")]
|
||||
public async FTask<IActionResult> Greet()
|
||||
{
|
||||
Log.Debug($"HelloController Thread.CurrentThread.ManagedThreadId:{Thread.CurrentThread.ManagedThreadId}");
|
||||
return Ok($"Hello from the Fantasy controller! _scene.SceneType:{_scene.SceneType} _scene.SceneType:{_scene.SceneConfigId}");
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Fantasy;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class ProductsController : ControllerBase
|
||||
{
|
||||
[HttpPost]
|
||||
public IActionResult MiniGame ([FromBody] Product product)
|
||||
{
|
||||
// 假设已经保存产品数据
|
||||
return Ok("Product created successfully");
|
||||
}
|
||||
}
|
||||
|
||||
public class Product
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Fantasy;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class UsersController : ControllerBase
|
||||
{
|
||||
private readonly Scene _scene;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数依赖注入
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
public UsersController(Scene scene)
|
||||
{
|
||||
_scene = scene;
|
||||
}
|
||||
|
||||
[HttpGet("{userId}")]
|
||||
public IActionResult GetUser(int userId)
|
||||
{
|
||||
return Ok($"User ID: {userId}");
|
||||
}
|
||||
|
||||
[HttpPost("register")]
|
||||
public IActionResult RegisterUser([FromBody] HttpUser user)
|
||||
{
|
||||
return Ok("User registered successfully");
|
||||
}
|
||||
|
||||
[HttpGet("greet")]
|
||||
public IActionResult Greet()
|
||||
{
|
||||
Log.Debug($"HelloController Thread.CurrentThread.ManagedThreadId:{Thread.CurrentThread.ManagedThreadId}");
|
||||
return Ok($"Hello from the Fantasy controller! _scene.SceneType:{_scene.SceneType} _scene.SceneType:{_scene.SceneConfigId}");
|
||||
}
|
||||
}
|
||||
|
||||
public class HttpUser
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Api\Middlewares\" />
|
||||
<Folder Include="Game\Condition\" />
|
||||
<Folder Include="Game\Mail\Handler\" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -21,4 +21,5 @@
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AScene_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F3cbbaf32e578423d8d0163d75da8233f87e00_003F6a_003F5adfe93e_003FScene_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASerializerManager_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F199e3c534d1e41cbb9a3a30bbf9ac93bde200_003F9f_003Fa4f53cf4_003FSerializerManager_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASortedOneToManyList_00602_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F3cbbaf32e578423d8d0163d75da8233f87e00_003F12_003Fcfa98068_003FSortedOneToManyList_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AUseExtensions_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fd455287e79b847419df3187cd3b7294f50938_003F45_003Fe5410c4e_003FUseExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AWorld_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F3cbbaf32e578423d8d0163d75da8233f87e00_003F4f_003F90b7c061_003FWorld_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
||||
Reference in New Issue
Block a user