移除api项目,合并至Server

This commit is contained in:
Gui.H 2022-12-03 22:26:17 +08:00
parent aaa75c3d64
commit a0d15a0e38
12 changed files with 369 additions and 133 deletions

View File

@ -5,10 +5,10 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="7.0.0-preview.3.22175.4" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="7.0.0" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="5.0.0-dev-00095" /> <PackageReference Include="Serilog.Extensions.Hosting" Version="5.0.1" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.3.1-dev-00337" /> <PackageReference Include="Serilog.Settings.Configuration" Version="3.5.0-dev-00359" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.2-dev-00890" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.1.1-dev-00896" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.1-dev-00947" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.1-dev-00947" />
</ItemGroup> </ItemGroup>

View File

@ -64,7 +64,7 @@ namespace FastTunnel.Core.Client
internal void ClientLogout(TunnelClient client) internal void ClientLogout(TunnelClient client)
{ {
Interlocked.Decrement(ref ConnectedClientCount); Interlocked.Decrement(ref ConnectedClientCount);
logger.LogInformation($"客户端关闭 {client.RemoteIpAddress} 当前在线数:{ConnectedClientCount}统计CLIENT连接数{FastTunnelClientHandler.ConnectionCount}"); logger.LogInformation($"客户端关闭 {client.RemoteIpAddress} 当前在线数:{ConnectedClientCount}统计CLIENT连接数{FastTunnelClientHandler.ConnectionCount - 1}");
Clients.Remove(client); Clients.Remove(client);
client.Logout(); client.Logout();
} }

View File

@ -0,0 +1,90 @@
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
// Copyright (c) 2019 Gui.H
using FastTunnel.Api.Models;
using FastTunnel.Core.Config;
using FastTunnel.Server.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
namespace FastTunnel.Api.Controllers
{
public class AccountController : BaseController
{
readonly IOptionsMonitor<DefaultServerConfig> serverOptionsMonitor;
public AccountController(IOptionsMonitor<DefaultServerConfig> optionsMonitor)
{
serverOptionsMonitor = optionsMonitor;
}
/// <summary>
/// 获取Token
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpPost]
public ApiResponse GetToken(GetTokenRequest request)
{
if ((serverOptionsMonitor.CurrentValue?.Api?.Accounts?.Length ?? 0) == 0)
{
ApiResponse.errorCode = ErrorCodeEnum.NoAccount;
ApiResponse.errorMessage = "账号或密码错误";
return ApiResponse;
}
var account = serverOptionsMonitor.CurrentValue.Api.Accounts.FirstOrDefault((x) =>
{
return x.Name.Equals(request.name) && x.Password.Equals(request.password);
});
if (account == null)
{
ApiResponse.errorCode = ErrorCodeEnum.NoAccount;
ApiResponse.errorMessage = "账号或密码错误";
return ApiResponse;
}
// 生成Token
var claims = new[] {
new Claim("Name", account.Name)
};
ApiResponse.data = GenerateToken(
claims,
serverOptionsMonitor.CurrentValue.Api.JWT.IssuerSigningKey,
serverOptionsMonitor.CurrentValue.Api.JWT.Expires,
serverOptionsMonitor.CurrentValue.Api.JWT.ValidIssuer,
serverOptionsMonitor.CurrentValue.Api.JWT.ValidAudience);
return ApiResponse;
}
public static string GenerateToken(
IEnumerable<Claim> claims, string Secret, int expiresMinutes = 60, string issuer = null, string audience = null)
{
var key = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(Secret));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var securityToken = new JwtSecurityToken(
issuer: issuer,
audience: audience,
claims: claims,
expires: DateTime.Now.AddMinutes(expiresMinutes),
signingCredentials: creds);
return new JwtSecurityTokenHandler().WriteToken(securityToken);
}
}
}

View File

@ -0,0 +1,22 @@
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
// Copyright (c) 2019 Gui.H
using FastTunnel.Api.Filters;
using FastTunnel.Server.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace FastTunnel.Api.Controllers
{
[Authorize]
[Route("api/[controller]/[action]")]
[ApiController]
[ServiceFilter(typeof(CustomExceptionFilterAttribute))]
public class BaseController : ControllerBase
{
protected ApiResponse ApiResponse = new ApiResponse();
}
}

View File

@ -0,0 +1,100 @@
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
// Copyright (c) 2019 Gui.H
using FastTunnel.Core.Client;
using FastTunnel.Server.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace FastTunnel.Api.Controllers;
public class SystemController : BaseController
{
readonly FastTunnelServer fastTunnelServer;
public SystemController(FastTunnelServer fastTunnelServer)
{
this.fastTunnelServer = fastTunnelServer;
}
/// <summary>
/// 获取当前等待响应的请求
/// </summary>
/// <returns></returns>
[HttpGet]
public ApiResponse GetResponseTempList()
{
ApiResponse.data = new
{
Count = fastTunnelServer.ResponseTasks.Count,
Rows = fastTunnelServer.ResponseTasks.Select(x => new
{
x.Key
})
};
return ApiResponse;
}
/// <summary>
/// 获取当前映射的所有站点信息
/// </summary>
/// <returns></returns>
[HttpGet]
public ApiResponse GetAllWebList()
{
ApiResponse.data = new
{
Count = fastTunnelServer.WebList.Count,
Rows = fastTunnelServer.WebList.Select(x => new { x.Key, x.Value.WebConfig.LocalIp, x.Value.WebConfig.LocalPort })
};
return ApiResponse;
}
/// <summary>
/// 获取服务端配置信息
/// </summary>
/// <returns></returns>
[HttpGet]
public ApiResponse GetServerOption()
{
ApiResponse.data = fastTunnelServer.ServerOption;
return ApiResponse;
}
/// <summary>
/// 获取所有端口转发映射列表
/// </summary>
/// <returns></returns>
[HttpGet]
public ApiResponse GetAllForwardList()
{
ApiResponse.data = new
{
Count = fastTunnelServer.ForwardList.Count,
Rows = fastTunnelServer.ForwardList.Select(x => new { x.Key, x.Value.SSHConfig.LocalIp, x.Value.SSHConfig.LocalPort, x.Value.SSHConfig.RemotePort })
};
return ApiResponse;
}
/// <summary>
/// 获取当前客户端在线数量
/// </summary>
/// <returns></returns>
[HttpGet]
public ApiResponse GetOnlineClientCount()
{
ApiResponse.data = fastTunnelServer.ConnectedClientCount;
return ApiResponse;
}
}

View File

@ -12,19 +12,18 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.4" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="7.0.0-preview.3.22175.4" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0-preview.3.22175.4" /> <PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="7.0.0-preview.3.22175.4" /> <PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="7.0.0" />
<PackageReference Include="Serilog.AspNetCore" Version="6.0.0-dev-00265" /> <PackageReference Include="Serilog.AspNetCore" Version="6.1.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(Configuration)'=='Debug'"> <ItemGroup Condition="'$(Configuration)'=='Debug'">
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.3.1" /> <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.3.1" /> <PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.4.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\FastTunnel.Api\FastTunnel.Api.csproj" />
<ProjectReference Include="..\FastTunnel.Core\FastTunnel.Core.csproj" /> <ProjectReference Include="..\FastTunnel.Core\FastTunnel.Core.csproj" />
</ItemGroup> </ItemGroup>

View File

@ -0,0 +1,39 @@
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
// Copyright (c) 2019 Gui.H
using FastTunnel.Server.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
namespace FastTunnel.Api.Filters
{
public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
readonly ILogger<CustomExceptionFilterAttribute> _logger;
public CustomExceptionFilterAttribute(ILogger<CustomExceptionFilterAttribute> logger)
{
_logger = logger;
}
public override void OnException(ExceptionContext context)
{
_logger.LogError(context.Exception, "【全局异常捕获】");
var res = new ApiResponse()
{
errorCode = ErrorCodeEnum.Exception,
data = null,
errorMessage = context.Exception.Message,
};
var result = new JsonResult(res) { StatusCode = 200 };
context.Result = result;
context.ExceptionHandled = true;
}
}
}

View File

@ -0,0 +1,32 @@
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
// Copyright (c) 2019 Gui.H
namespace FastTunnel.Server.Models
{
public class ApiResponse
{
/// <summary>
/// 错误码
/// 0 成功,其他为失败
/// </summary>
public ErrorCodeEnum errorCode { get; set; }
public string errorMessage { get; set; }
public object data { get; set; }
}
public enum ErrorCodeEnum
{
NONE = 0,
AuthError = 1,
Exception = 2,
NoAccount = 3,
}
}

View File

@ -0,0 +1,19 @@
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
// Copyright (c) 2019 Gui.H
using System.ComponentModel.DataAnnotations;
namespace FastTunnel.Api.Models
{
public class GetTokenRequest
{
[Required]
public string name { get; set; }
[Required]
public string password { get; set; }
}
}

View File

@ -6,8 +6,11 @@
using System.Net.Http; using System.Net.Http;
using System.Net.Sockets; using System.Net.Sockets;
using FastTunnel.Core.Extensions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Serilog; using Serilog;
@ -27,8 +30,58 @@ public class Program
try try
{ {
CreateHostBuilder(args).Build().Run(); var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
Args = args
});
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Host.UseSerilog((context, services, configuration) => configuration
.ReadFrom.Configuration(context.Configuration)
.ReadFrom.Services(services)
.Enrich.FromLogContext()
.WriteTo.Console());
(builder.Configuration as IConfigurationBuilder).AddJsonFile("config/appsettings.json", optional: false, reloadOnChange: true);
(builder.Configuration as IConfigurationBuilder).AddJsonFile($"config/appsettings.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: true); ;
// -------------------FastTunnel STEP1 OF 3------------------
builder.Services.AddFastTunnelServer(builder.Configuration.GetSection("FastTunnel"));
// -------------------FastTunnel STEP1 END-------------------
builder.Host.UseWindowsService();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
// -------------------FastTunnel STEP2 OF 3------------------
app.UseFastTunnelServer();
// -------------------FastTunnel STEP2 END-------------------
app.MapFastTunnelServer();
app.Run();
} }
catch (System.Exception ex) catch (System.Exception ex)
{ {
@ -36,31 +89,4 @@ public class Program
throw; throw;
} }
} }
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.UseSerilog((context, services, configuration) => configuration
.ReadFrom.Configuration(context.Configuration)
.ReadFrom.Services(services)
.Enrich.FromLogContext()
.WriteTo.Console())
.UseWindowsService()
.ConfigureWebHost(webHostBuilder =>
{
// Use FastTunnelHostingStartup
webHostBuilder.UseSetting(WebHostDefaults.HostingStartupAssembliesKey, "FastTunnel.Api");
webHostBuilder.ConfigureAppConfiguration((hostingContext, config) =>
{
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("config/appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"config/appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
});
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
} }

View File

@ -1,84 +0,0 @@
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
// Copyright (c) 2019 Gui.H
using FastTunnel.Core.Extensions;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using System;
using FastTunnel.Core.Config;
using System.Text;
using FastTunnel.Api.Filters;
#if DEBUG
using Microsoft.OpenApi.Models;
#endif
namespace FastTunnel.Server;
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization();
services.AddControllers();
#if DEBUG
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v2", new OpenApiInfo { Title = "FastTunel.Api", Version = "v2" });
});
#endif
// -------------------FastTunnel STEP1 OF 3------------------
services.AddFastTunnelServer(Configuration.GetSection("FastTunnel"));
// -------------------FastTunnel STEP1 END-------------------
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
#if DEBUG
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v2/swagger.json", "FastTunel.WebApi v2"));
#endif
}
app.UseRouting();
// -------------------FastTunnel STEP2 OF 3------------------
app.UseFastTunnelServer();
// -------------------FastTunnel STEP2 END-------------------
app.UseStaticFiles();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
// -------------------FastTunnel STEP3 OF 3------------------
endpoints.MapFastTunnelServer();
// -------------------FastTunnel STEP3 END-------------------
});
}
}

View File

@ -11,15 +11,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastTunnel.Server", "FastTu
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{0E2A9DA2-26AE-4657-B4C5-3A913E2F5A3C}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{0E2A9DA2-26AE-4657-B4C5-3A913E2F5A3C}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastTunnel.Api", "FastTunnel.Api\FastTunnel.Api.csproj", "{7D560A9A-E480-40F4-AAF7-398447438255}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{54494A47-33E6-488B-B7D4-DBE8FD34916A}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{54494A47-33E6-488B-B7D4-DBE8FD34916A}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig .editorconfig = .editorconfig
.github\workflows\dotnetcore.yml = .github\workflows\dotnetcore.yml .github\workflows\dotnetcore.yml = .github\workflows\dotnetcore.yml
EndProjectSection EndProjectSection
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastTunnel.Core.Client", "FastTunnel.Core.Client\FastTunnel.Core.Client.csproj", "{67DB3ED6-B1DD-49AA-8C5D-34FABC3C643B}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastTunnel.Core.Client", "FastTunnel.Core.Client\FastTunnel.Core.Client.csproj", "{67DB3ED6-B1DD-49AA-8C5D-34FABC3C643B}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -39,10 +37,6 @@ Global
{DEF2E322-9075-4C3F-9967-7EAF0EE28CEB}.Debug|Any CPU.Build.0 = Debug|Any CPU {DEF2E322-9075-4C3F-9967-7EAF0EE28CEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DEF2E322-9075-4C3F-9967-7EAF0EE28CEB}.Release|Any CPU.ActiveCfg = Release|Any CPU {DEF2E322-9075-4C3F-9967-7EAF0EE28CEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DEF2E322-9075-4C3F-9967-7EAF0EE28CEB}.Release|Any CPU.Build.0 = Release|Any CPU {DEF2E322-9075-4C3F-9967-7EAF0EE28CEB}.Release|Any CPU.Build.0 = Release|Any CPU
{7D560A9A-E480-40F4-AAF7-398447438255}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7D560A9A-E480-40F4-AAF7-398447438255}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7D560A9A-E480-40F4-AAF7-398447438255}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7D560A9A-E480-40F4-AAF7-398447438255}.Release|Any CPU.Build.0 = Release|Any CPU
{67DB3ED6-B1DD-49AA-8C5D-34FABC3C643B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {67DB3ED6-B1DD-49AA-8C5D-34FABC3C643B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{67DB3ED6-B1DD-49AA-8C5D-34FABC3C643B}.Debug|Any CPU.Build.0 = Debug|Any CPU {67DB3ED6-B1DD-49AA-8C5D-34FABC3C643B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{67DB3ED6-B1DD-49AA-8C5D-34FABC3C643B}.Release|Any CPU.ActiveCfg = Release|Any CPU {67DB3ED6-B1DD-49AA-8C5D-34FABC3C643B}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -53,7 +47,6 @@ Global
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{C8ADFEB1-59DB-4CE3-8D04-5B547107BCCB} = {0E2A9DA2-26AE-4657-B4C5-3A913E2F5A3C} {C8ADFEB1-59DB-4CE3-8D04-5B547107BCCB} = {0E2A9DA2-26AE-4657-B4C5-3A913E2F5A3C}
{7D560A9A-E480-40F4-AAF7-398447438255} = {0E2A9DA2-26AE-4657-B4C5-3A913E2F5A3C}
{67DB3ED6-B1DD-49AA-8C5D-34FABC3C643B} = {0E2A9DA2-26AE-4657-B4C5-3A913E2F5A3C} {67DB3ED6-B1DD-49AA-8C5D-34FABC3C643B} = {0E2A9DA2-26AE-4657-B4C5-3A913E2F5A3C}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution