Skip to content

Commit

Permalink
合并
Browse files Browse the repository at this point in the history
  • Loading branch information
nnhy committed Jun 2, 2024
2 parents 7d770f4 + bf5b945 commit 7d01727
Show file tree
Hide file tree
Showing 71 changed files with 8,133 additions and 261 deletions.
3 changes: 0 additions & 3 deletions .gitmodules

This file was deleted.

13 changes: 4 additions & 9 deletions NewLife.Remoting.Extensions/Common/BaseController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
using NewLife.Remoting.Extensions.Services;
using NewLife.Serialization;
using NewLife.Web;
using static NewLife.Remoting.ApiHttpClient;
using IWebFilter = Microsoft.AspNetCore.Mvc.Filters.IActionFilter;

namespace NewLife.Remoting.Extensions;
Expand All @@ -25,16 +24,13 @@ public abstract class BaseController : ControllerBase, IWebFilter
/// <summary>令牌</summary>
public String? Token { get; private set; }

/// <summary>应用信息</summary>
public IAppInfo App { get; set; } = null!;

/// <summary>令牌对象</summary>
public JwtBuilder Jwt { get; set; } = null!;

/// <summary>用户主机</summary>
public String UserHost => HttpContext.GetUserHost();

private IDictionary<String, Object>? _args;
private IDictionary<String, Object?>? _args;
private readonly TokenService _tokenService;
private readonly ITokenSetting _setting;
#endregion
Expand Down Expand Up @@ -81,11 +77,10 @@ void IWebFilter.OnActionExecuting(ActionExecutingContext context)
/// <returns></returns>
protected virtual Boolean OnAuthorize(String token)
{
var (jwt, app) = _tokenService.DecodeToken(token, _setting.TokenSecret);
App = app;
var jwt = _tokenService.DecodeToken(token, _setting.TokenSecret);
Jwt = jwt;

return app != null;
return jwt != null;
}

void IWebFilter.OnActionExecuted(ActionExecutedContext context)
Expand Down Expand Up @@ -113,6 +108,6 @@ private void WriteError(Exception ex, ActionContext context)
/// <param name="action"></param>
/// <param name="success"></param>
/// <param name="message"></param>
protected virtual void WriteLog(String action, Boolean success, String message) => App.WriteLog(action, success, message, UserHost, Jwt?.Id);
protected virtual void WriteLog(String action, Boolean success, String message) => XTrace.WriteLine($"[{action}]{message}");
#endregion
}
58 changes: 50 additions & 8 deletions NewLife.Remoting.Extensions/Common/OAuthController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ namespace NewLife.Remoting.Extensions;

/// <summary>OAuth服务。向应用提供验证服务</summary>
[Route("[controller]/[action]")]
public class OAuthController : ControllerBase
public abstract class OAuthController<TApp> : ControllerBase where TApp : IAppInfo
{
private readonly TokenService _tokenService;
private readonly ITokenSetting _setting;

/// <summary>实例化</summary>
/// <param name="tokenService"></param>
/// <param name="setting"></param>
public OAuthController(TokenService tokenService, ITokenSetting setting)
{
_tokenService = tokenService;
Expand All @@ -40,7 +41,9 @@ public TokenModel Token([FromBody] TokenInModel model)
// 密码模式
if (model.grant_type == "password")
{
var app = _tokenService.Authorize(model.UserName, model.Password, set.AutoRegister, ip);
if (model.UserName.IsNullOrEmpty()) throw new ArgumentNullException(nameof(model.UserName));

var app = Authorize(model.UserName, model.Password, set.AutoRegister, ip);

var tokenModel = _tokenService.IssueToken(app.Name, set.TokenSecret, set.TokenExpire, clientId);

Expand All @@ -51,12 +54,14 @@ public TokenModel Token([FromBody] TokenInModel model)
// 刷新令牌
else if (model.grant_type == "refresh_token")
{
if (model.refresh_token.IsNullOrEmpty()) throw new ArgumentNullException(nameof(model.refresh_token));

var (jwt, ex) = _tokenService.DecodeTokenWithError(model.refresh_token, set.TokenSecret);

// 验证应用
var app = _tokenService.Provider.FindByName(jwt?.Subject);
var app = FindByName(jwt?.Subject);
if (app == null || !app.Enable)
ex ??= new ApiException(403, $"无效应用[{jwt.Subject}]");
ex ??= new ApiException(ApiCode.Forbidden, $"无效应用[{jwt.Subject}]");

if (clientId.IsNullOrEmpty()) clientId = jwt.Id;

Expand All @@ -77,33 +82,70 @@ public TokenModel Token([FromBody] TokenInModel model)
}
catch (Exception ex)
{
var app = _tokenService.Provider.FindByName(model.UserName);
var app = FindByName(model.UserName!);
app?.WriteLog("Authorize", false, ex.ToString(), ip, clientId);

throw;
}
}

/// <summary>验证应用密码,不存在时新增</summary>
/// <param name="username"></param>
/// <param name="password"></param>
/// <param name="autoRegister"></param>
/// <param name="ip"></param>
/// <returns></returns>
protected TApp Authorize(String username, String? password, Boolean autoRegister, String? ip = null)
{
if (username.IsNullOrEmpty()) throw new ArgumentNullException(nameof(username));
//if (password.IsNullOrEmpty()) throw new ArgumentNullException(nameof(password));

// 查找应用
var app = FindByName(username);
// 查找或创建应用,避免多线程创建冲突
app ??= Register(username, password, autoRegister, ip);
if (app == null) throw new ApiException(ApiCode.NotFound, $"[{username}]无效!");

//// 检查黑白名单
//if (!app.ValidSource(ip))
// throw new ApiException(ApiCode.Forbidden, $"应用[{username}]禁止{ip}访问!");

// 检查应用有效性
if (!app.Enable) throw new ApiException(ApiCode.Forbidden, $"[{username}]已禁用!");
//if (!app.Secret.IsNullOrEmpty() && password != app.Secret) throw new ApiException(401, $"非法访问应用[{username}]!");
if (!OnAuthorize(app, password, ip)) throw new ApiException(ApiCode.Unauthorized, $"非法访问[{username}]!");

return app;
}

protected abstract TApp FindByName(String username);

protected abstract TApp Register(String username, String? password, Boolean autoRegister, String? ip = null);

protected abstract Boolean OnAuthorize(TApp app, String? password, String? ip = null);

/// <summary>根据令牌获取应用信息,同时也是验证令牌是否有效</summary>
/// <param name="token"></param>
/// <returns></returns>
[ApiFilter]
public Object Info(String token)
{
var set = _setting;
var (_, app) = _tokenService.DecodeToken(token, set.TokenSecret);
var jwt = _tokenService.DecodeToken(token, set.TokenSecret);
var name = jwt?.Subject;
var app = name.IsNullOrEmpty() ? default : FindByName(name);
if (app is IModel model)
return new
{
Id = model["Id"],
app.Name,
Name = name,
DisplayName = model["DisplayName"],
Category = model["Category"],
};
else
return new
{
app.Name,
Name = name,
};
}
}
25 changes: 25 additions & 0 deletions NewLife.Remoting.Extensions/Models/IAppInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace NewLife.Remoting.Extensions.Models;

/// <summary>应用信息接口</summary>
public interface IAppInfo
{
/// <summary>名称</summary>
String Name { get; }

/// <summary>启用</summary>
Boolean Enable { get; }

/// <summary>验证授权</summary>
/// <param name="password"></param>
/// <param name="ip"></param>
/// <returns></returns>
Boolean Authorize(String? password, String? ip = null);

/// <summary>写日志</summary>
/// <param name="action"></param>
/// <param name="success"></param>
/// <param name="message"></param>
/// <param name="ip"></param>
/// <param name="clientId"></param>
void WriteLog(String action, Boolean success, String message, String? ip, String? clientId);
}
19 changes: 0 additions & 19 deletions NewLife.Remoting.Extensions/Models/IAppProvider.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFrameworks>net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
<AssemblyTitle>RPC服务扩展</AssemblyTitle>
<Description>RPC远程过程调用,二进制封装,提供高吞吐低延迟的高性能RPC框架</Description>
<Company>新生命开发团队</Company>
Expand Down
83 changes: 8 additions & 75 deletions NewLife.Remoting.Extensions/Services/TokenService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Reflection;
using NewLife.Remoting.Extensions.Models;
using NewLife.Security;
using NewLife.Web;

Expand All @@ -8,44 +7,11 @@ namespace NewLife.Remoting.Extensions.Services;
/// <summary>应用服务</summary>
public class TokenService
{
#region 公共
/// <summary>应用信息提供者</summary>
public IAppProvider? Provider { get; set; }
#endregion

/// <summary>验证应用密码,不存在时新增</summary>
/// <param name="username"></param>
/// <param name="password"></param>
/// <param name="autoRegister"></param>
/// <param name="ip"></param>
/// <returns></returns>
public IAppInfo Authorize(String username, String password, Boolean autoRegister, String? ip = null)
{
if (username.IsNullOrEmpty()) throw new ArgumentNullException(nameof(username));
//if (password.IsNullOrEmpty()) throw new ArgumentNullException(nameof(password));
if (Provider == null) throw new ArgumentNullException(nameof(Provider));

// 查找应用
var app = Provider.FindByName(username);
// 查找或创建应用,避免多线程创建冲突
app ??= Provider.Register(username, password, autoRegister, ip);

//// 检查黑白名单
//if (!app.ValidSource(ip))
// throw new ApiException(403, $"应用[{username}]禁止{ip}访问!");

// 检查应用有效性
if (!app.Enable) throw new ApiException(403, $"应用[{username}]已禁用!");
//if (!app.Secret.IsNullOrEmpty() && password != app.Secret) throw new ApiException(401, $"非法访问应用[{username}]!");
if (!app.Authorize(password, ip)) throw new ApiException(401, $"非法访问应用[{username}]!");

return app;
}

/// <summary>颁发令牌</summary>
/// <param name="name"></param>
/// <param name="secret"></param>
/// <param name="expire"></param>
/// <param name="id"></param>
/// <returns></returns>
public TokenModel IssueToken(String name, String secret, Int32 expire, String? id = null)
{
Expand All @@ -55,7 +21,7 @@ public TokenModel IssueToken(String name, String secret, Int32 expire, String? i
var ss = secret.Split(':');
var jwt = new JwtBuilder
{
Issuer = Assembly.GetEntryAssembly().GetName().Name,
Issuer = Assembly.GetEntryAssembly()?.GetName().Name,
Subject = name,
Id = id,
Expire = DateTime.Now.AddSeconds(expire),
Expand All @@ -66,10 +32,10 @@ public TokenModel IssueToken(String name, String secret, Int32 expire, String? i

return new TokenModel
{
AccessToken = jwt.Encode(null),
AccessToken = jwt.Encode(null!),
TokenType = jwt.Type ?? "JWT",
ExpireIn = expire,
RefreshToken = jwt.Encode(null),
RefreshToken = jwt.Encode(null!),
};
}

Expand Down Expand Up @@ -112,7 +78,7 @@ public TokenModel IssueToken(String name, String secret, Int32 expire, String? i
};

Exception? ex = null;
if (!jwt.TryDecode(token, out var message)) ex = new ApiException(403, $"[{jwt.Subject}]非法访问 {message}");
if (!jwt.TryDecode(token, out var message)) ex = new ApiException(ApiCode.Forbidden, $"[{jwt.Subject}]非法访问 {message}");

return (jwt, ex);
}
Expand All @@ -121,10 +87,9 @@ public TokenModel IssueToken(String name, String secret, Int32 expire, String? i
/// <param name="token"></param>
/// <param name="tokenSecret"></param>
/// <returns></returns>
public (JwtBuilder, IAppInfo) DecodeToken(String token, String tokenSecret)
public JwtBuilder DecodeToken(String token, String tokenSecret)
{
if (token.IsNullOrEmpty()) throw new ArgumentNullException(nameof(token));
if (Provider == null) throw new ArgumentNullException(nameof(Provider));

// 解码令牌
var ss = tokenSecret.Split(':');
Expand All @@ -134,40 +99,8 @@ public TokenModel IssueToken(String name, String secret, Int32 expire, String? i
Secret = ss[1],
};
if (!jwt.TryDecode(token, out var message) || jwt.Subject.IsNullOrEmpty())
throw new ApiException(403, $"非法访问[{jwt.Subject}],{message}");

// 验证应用
var app = Provider.FindByName(jwt.Subject)
?? throw new ApiException(403, $"无效应用[{jwt.Subject}]");
if (!app.Enable) throw new ApiException(403, $"已停用应用[{jwt.Subject}]");

return (jwt, app);
}

/// <summary>解码令牌</summary>
/// <param name="token"></param>
/// <param name="tokenSecret"></param>
/// <returns></returns>
public (IAppInfo?, Exception?) TryDecodeToken(String token, String tokenSecret)
{
if (token.IsNullOrEmpty()) throw new ArgumentNullException(nameof(token));
if (Provider == null) throw new ArgumentNullException(nameof(Provider));

// 解码令牌
var ss = tokenSecret.Split(':');
var jwt = new JwtBuilder
{
Algorithm = ss[0],
Secret = ss[1],
};

Exception? ex = null;
if (!jwt.TryDecode(token, out var message)) ex = new ApiException(403, $"非法访问 {message}");

// 验证应用
var app = Provider.FindByName(jwt.Subject);
if ((app == null || !app.Enable) && ex == null) ex = new ApiException(401, $"无效应用[{jwt.Subject}]");
throw new ApiException(ApiCode.Forbidden, $"非法访问[{jwt.Subject}],{message}");

return (app, ex);
return jwt;
}
}
4 changes: 4 additions & 0 deletions NewLife.Remoting/ApiMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,8 @@ public class ApiMessage

/// <summary>数据。请求参数或响应内容</summary>
public Packet? Data { get; set; }

/// <summary>已重载。友好表示该消息</summary>
/// <returns></returns>
public override String ToString() => Code > 0 ? $"{Action}[{Code}]" : Action;
}
Loading

0 comments on commit 7d01727

Please sign in to comment.