增加api接口jwt认证逻辑

This commit is contained in:
Gui.H 2021-09-09 14:47:49 +08:00
parent f4c4c15736
commit f2af2bb4f6
13 changed files with 305 additions and 32 deletions

View 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);
}
}
}

View File

@ -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

View File

@ -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>

View 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;
}
}
}

View File

@ -21,5 +21,11 @@ namespace FastTunnel.Server.Models
public enum ErrorCodeEnum
{
NONE = 0,
AuthError = 1,
Exception = 2,
NoAccount = 3,
}
}

View 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; }
}
}

View File

@ -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"
// CNAMEA
// [] CNAMEA
// "WWW": [ "www.abc.com", "test111.test.cc" ]
}
],
/**
*
* []
* 穿TCP
* linux#ssh -oPort=12701 {root}@{ServerAddr} ServerAddr iproot
* 访访
*/
"Forwards": [
{
// [] ip
"LocalIp": "127.0.0.1",
"LocalPort": 3389, // windows3389
"RemotePort": 1274 // 访 ip:1274 window
// [] windows3389
"LocalPort": 3389,
// [] 访 ip:1274 window
"RemotePort": 1274
},
{
"LocalIp": "127.0.0.1",
"LocalPort": 8090, // windows3389
"RemotePort": 1275 // 访 ip:1274 window
"LocalPort": 3306, // mysql
"RemotePort": 1275 // 访 ip:1275 mysql
}
]
}

View File

@ -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; }
}
}
}

View File

@ -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" />

View File

@ -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>

View File

@ -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-------------------
});
}
}

View File

@ -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" ],
// SSHForward.false
// Forward.false
"EnableForward": true,
// Token,
"Token": "TOKEN_FOR_CLIENT_AUTHENTICATION"
// Token
"Token": "TOKEN_FOR_CLIENT_AUTHENTICATION",
/**
* 访apiJWT
*/
"Api": {
"JWT": {
"ClockSkew": 10,
"ValidAudience": "https://suidao.io",
"ValidIssuer": "FastTunnel",
"IssuerSigningKey": "This is IssuerSigningKey",
"Expires": 120
},
"Accounts": [
{
"Name": "admin",
"Password": "admin123"
}
]
}
}
}

View File

@ -0,0 +1 @@
index