mirror of
https://github.com/FastTunnel/FastTunnel.git
synced 2024-09-20 23:48:30 +08:00
增加api接口jwt认证逻辑
This commit is contained in:
parent
f4c4c15736
commit
f2af2bb4f6
87
FastTunnel.Api/Controllers/AccountController.cs
Normal file
87
FastTunnel.Api/Controllers/AccountController.cs
Normal file
|
@ -0,0 +1,87 @@
|
|||
using FastTunnel.Api.Models;
|
||||
using FastTunnel.Core.Client;
|
||||
using FastTunnel.Core.Config;
|
||||
using FastTunnel.Server.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
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;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastTunnel.Api.Controllers
|
||||
{
|
||||
public class AccountController : BaseController
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using FastTunnel.Server.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
|
@ -8,6 +9,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace FastTunnel.Api.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
[Route("api/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class BaseController : ControllerBase
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.12.2" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.12.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
38
FastTunnel.Api/Filters/CustomExceptionFilterAttribute.cs
Normal file
38
FastTunnel.Api/Filters/CustomExceptionFilterAttribute.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
using FastTunnel.Server.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,5 +21,11 @@ namespace FastTunnel.Server.Models
|
|||
public enum ErrorCodeEnum
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
AuthError = 1,
|
||||
|
||||
Exception = 2,
|
||||
|
||||
NoAccount = 3,
|
||||
}
|
||||
}
|
||||
|
|
18
FastTunnel.Api/Models/GetTokenRequest.cs
Normal file
18
FastTunnel.Api/Models/GetTokenRequest.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastTunnel.Api.Models
|
||||
{
|
||||
public class GetTokenRequest
|
||||
{
|
||||
[Required]
|
||||
public string name { get; set; }
|
||||
|
||||
[Required]
|
||||
public string password { get; set; }
|
||||
}
|
||||
}
|
|
@ -7,54 +7,58 @@
|
|||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
// 是否启用文件日志输出
|
||||
"EnableFileLog": false,
|
||||
"ClientSettings": {
|
||||
"Server": {
|
||||
// 与服务端通讯协议
|
||||
"Protocol": "ws", // ws(http)或wss(https)
|
||||
// 服务端ip/域名
|
||||
// [必选] 与服务端通讯协议(来自服务端配置文件的urls参数)
|
||||
// 可选参数:ws(http)或wss(https)
|
||||
"Protocol": "ws",
|
||||
// [必选] 服务端ip/域名(来自服务端配置文件的urls参数)
|
||||
"ServerAddr": "test.cc",
|
||||
// 服务端监听的通信端口
|
||||
// [必选] 服务端监听的通信端口(来自服务端配置文件的urls参数)
|
||||
"ServerPort": 1270
|
||||
},
|
||||
|
||||
// 服务端Token验证
|
||||
// [可选],服务端Token,必须与服务端配置一致,否则拒绝登录。
|
||||
"Token": "TOKEN_FOR_CLIENT_AUTHENTICATION",
|
||||
/**
|
||||
* 通过自定义域名访问内网服务,需要有自己的域名
|
||||
* 可穿透所有TCP上层协议
|
||||
* [可选] 内网web节点配置
|
||||
*/
|
||||
"Webs": [
|
||||
{
|
||||
// 本地站点所在内网的ip
|
||||
// [必选] 内网站点所在内网的ip
|
||||
"LocalIp": "127.0.0.1",
|
||||
// 站点监听的端口号
|
||||
// [必选] 内网站点监听的端口号
|
||||
"LocalPort": 8090,
|
||||
|
||||
// 子域名, 访问本站点时的url为 http://{SubDomain}.{WebDomain}:{WebProxyPort}/
|
||||
"SubDomain": "test" // test.test.cc
|
||||
// [必选] 子域名, 访问本站点时的url为 http://${SubDomain}.${WebDomain}:${ServerPort}
|
||||
"SubDomain": "test"
|
||||
|
||||
// 附加域名,需要解析CNAME或A记录)
|
||||
// [可选] 附加域名,需要解析CNAME或A记录至当前子域名
|
||||
// "WWW": [ "www.abc.com", "test111.test.cc" ]
|
||||
}
|
||||
],
|
||||
|
||||
/**
|
||||
* 端口转发 通过专用端口代理,不需要有自己的域名
|
||||
* [可选] 端口转发 通过专用端口代理,不需要有自己的域名
|
||||
* 可穿透所有TCP上层协议
|
||||
* 远程linux示例:#ssh -oPort=12701 {root}@{ServerAddr} ServerAddr 填入服务端ip,root对应内网用户名
|
||||
* 通过服务端返回的访问方式进行访问即可
|
||||
*/
|
||||
"Forwards": [
|
||||
{
|
||||
// [必选] 内网服务所在主机ip
|
||||
"LocalIp": "127.0.0.1",
|
||||
"LocalPort": 3389, // windows远程桌面端口为3389
|
||||
"RemotePort": 1274 // 访问 服务端ip:1274 即可实现远程window桌面
|
||||
// [必选] 内网服务监听端口 windows远程桌面端口为3389
|
||||
"LocalPort": 3389,
|
||||
// [必选] 服务端端口 访问 服务端ip:1274 即可实现远程window桌面
|
||||
"RemotePort": 1274
|
||||
},
|
||||
{
|
||||
"LocalIp": "127.0.0.1",
|
||||
"LocalPort": 8090, // windows远程桌面端口为3389
|
||||
"RemotePort": 1275 // 访问 服务端ip:1274 即可实现远程window桌面
|
||||
"LocalPort": 3306, // mysql数据库默认端口
|
||||
"RemotePort": 1275 // 访问 服务端ip:1275 即可连接内网的mysql服务
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -14,5 +14,34 @@ namespace FastTunnel.Core.Config
|
|||
public bool EnableForward { get; set; } = false;
|
||||
|
||||
public string Token { get; set; }
|
||||
|
||||
public ApiOptions Api { get; set; }
|
||||
|
||||
public class ApiOptions
|
||||
{
|
||||
public JWTOptions JWT { get; set; }
|
||||
|
||||
public Account[] Accounts { get; set; }
|
||||
}
|
||||
|
||||
public class JWTOptions
|
||||
{
|
||||
public int ClockSkew { get; set; }
|
||||
|
||||
public string ValidAudience { get; set; }
|
||||
|
||||
public string ValidIssuer { get; set; }
|
||||
|
||||
public string IssuerSigningKey { get; set; }
|
||||
|
||||
public int Expires { get; set; }
|
||||
}
|
||||
|
||||
public class Account
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Password { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="5.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0-preview.4.21253.7" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="6.0.0-preview.4.21253.7" />
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<DeleteExistingFiles>False</DeleteExistingFiles>
|
||||
<ExcludeApp_Data>False</ExcludeApp_Data>
|
||||
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
|
||||
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
|
||||
<LastUsedPlatform>Any CPU</LastUsedPlatform>
|
||||
<PublishProvider>FileSystem</PublishProvider>
|
||||
<PublishUrl>bin\Release\net5.0\publish\</PublishUrl>
|
||||
<WebPublishMethod>FileSystem</WebPublishMethod>
|
||||
</PropertyGroup>
|
||||
</Project>
|
|
@ -1,17 +1,21 @@
|
|||
using FastTunnel.Core;
|
||||
using FastTunnel.Core.Config;
|
||||
using FastTunnel.Core.Extensions;
|
||||
using FastTunnel.Server.Models;
|
||||
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.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System;
|
||||
using FastTunnel.Core.Config;
|
||||
using System.Text;
|
||||
|
||||
#if DEBUG
|
||||
using Microsoft.OpenApi.Models;
|
||||
#endif
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastTunnel.Server
|
||||
{
|
||||
|
@ -27,6 +31,43 @@ namespace FastTunnel.Server
|
|||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
var serverOptions = Configuration.GetSection("FastTunnel").Get<DefaultServerConfig>();
|
||||
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuer = false,
|
||||
ValidateAudience = false,
|
||||
ValidateLifetime = true,
|
||||
ClockSkew = TimeSpan.FromSeconds(serverOptions.Api.JWT.ClockSkew),
|
||||
ValidateIssuerSigningKey = true,
|
||||
ValidAudience = serverOptions.Api.JWT.ValidAudience,
|
||||
ValidIssuer = serverOptions.Api.JWT.ValidIssuer,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(serverOptions.Api.JWT.IssuerSigningKey))
|
||||
};
|
||||
|
||||
options.Events = new JwtBearerEvents
|
||||
{
|
||||
OnChallenge = async context =>
|
||||
{
|
||||
context.HandleResponse();
|
||||
|
||||
context.Response.ContentType = "application/json;charset=utf-8";
|
||||
context.Response.StatusCode = StatusCodes.Status200OK;
|
||||
|
||||
await context.Response.WriteAsync(new ApiResponse
|
||||
{
|
||||
errorCode = ErrorCodeEnum.AuthError,
|
||||
errorMessage = context.Error ?? "Token is Required"
|
||||
}.ToJson());
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
services.AddAuthorization();
|
||||
|
||||
services.AddControllers();
|
||||
|
||||
#if DEBUG
|
||||
|
@ -37,8 +78,8 @@ namespace FastTunnel.Server
|
|||
#endif
|
||||
|
||||
// -------------------FastTunnel STEP1 OF 3------------------
|
||||
services.AddFastTunnelServer(Configuration.GetSection("ServerSettings"));
|
||||
// -------------------FastTunnel STEP1 END--------------------
|
||||
services.AddFastTunnelServer(Configuration.GetSection("FastTunnel"));
|
||||
// -------------------FastTunnel STEP1 END-------------------
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
|
@ -55,16 +96,22 @@ namespace FastTunnel.Server
|
|||
|
||||
// -------------------FastTunnel STEP2 OF 3------------------
|
||||
app.UseFastTunnelServer();
|
||||
// -------------------FastTunnel STEP2 END--------------------
|
||||
// -------------------FastTunnel STEP2 END-------------------
|
||||
|
||||
app.UseRouting();
|
||||
|
||||
// --------------------- Custom UI ----------------
|
||||
app.UseStaticFiles();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
// --------------------- Custom UI ----------------
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapControllers();
|
||||
// -------------------FastTunnel STEP3 OF 3------------------
|
||||
endpoints.MapFastTunnelServer();
|
||||
// -------------------FastTunnel STEP3 END--------------------
|
||||
// -------------------FastTunnel STEP3 END-------------------
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,19 +8,41 @@
|
|||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"urls": "http://*:1270;https://*:4443;", // Http&客户端通讯端口
|
||||
// Http&客户端通讯端口
|
||||
"urls": "http://*:1270",
|
||||
// 是否启用文件日志输出
|
||||
"EnableFileLog": false,
|
||||
"ServerSettings": {
|
||||
// 绑定的根域名
|
||||
"FastTunnel": {
|
||||
// 可选,绑定的根域名,
|
||||
// 客户端需配置SubDomain,实现 ${SubDomain}.${WebDomain}访问内网的站点,注意:需要通过域名访问网站时必选。
|
||||
"WebDomain": "test.cc",
|
||||
|
||||
// 可选,访问白名单,不在白名单的ip拒绝,为空时所有人有权限访问
|
||||
// 可选,访问白名单,为空时:所有人有权限访问,不为空时:不在白名单的ip拒绝。
|
||||
"WebAllowAccessIps": [ "192.168.0.101" ],
|
||||
|
||||
// 可选,是否开启SSH,禁用后不处理Forward类型端口转发.默认false。
|
||||
// 可选,是否开启端口转发代理,禁用后不处理Forward类型端口转发.默认false。
|
||||
"EnableForward": true,
|
||||
|
||||
// 可选,当不为空时,客户端也必须携带相同的Token,否则拒绝登录
|
||||
"Token": "TOKEN_FOR_CLIENT_AUTHENTICATION"
|
||||
// 可选,当不为空时,客户端也必须携带相同的Token,否则拒绝登录。
|
||||
"Token": "TOKEN_FOR_CLIENT_AUTHENTICATION",
|
||||
|
||||
/**
|
||||
* 访问api接口的JWT配置
|
||||
*/
|
||||
"Api": {
|
||||
"JWT": {
|
||||
"ClockSkew": 10,
|
||||
"ValidAudience": "https://suidao.io",
|
||||
"ValidIssuer": "FastTunnel",
|
||||
"IssuerSigningKey": "This is IssuerSigningKey",
|
||||
"Expires": 120
|
||||
},
|
||||
"Accounts": [
|
||||
{
|
||||
"Name": "admin",
|
||||
"Password": "admin123"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
1
FastTunnel.Server/wwwroot/index.html
Normal file
1
FastTunnel.Server/wwwroot/index.html
Normal file
|
@ -0,0 +1 @@
|
|||
index
|
Loading…
Reference in New Issue
Block a user