Skip to content

Commit

Permalink
引入IClientSetting,简化登录后保存密钥的机制
Browse files Browse the repository at this point in the history
  • Loading branch information
nnhy committed Jun 8, 2024
1 parent 9acd97d commit 1dcb3c1
Show file tree
Hide file tree
Showing 10 changed files with 105 additions and 38 deletions.
10 changes: 10 additions & 0 deletions NewLife.Remoting.Extensions/Common/BaseController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,16 @@ private void WriteError(Exception ex, ActionContext context)
protected virtual void OnWriteError(String action, String message) => WriteLog(action, false, message);
#endregion

#region 方法
///// <summary>设备登录</summary>
///// <param name="model"></param>
///// <returns></returns>
//[AllowAnonymous]
//[HttpPost(nameof(Login))]
//public LoginResponse Login(NewLife.Remoting.Models.LoginRequest model) => _deviceService.Login(model as LoginInfo, "Http", UserHost);

#endregion

#region 辅助
/// <summary>写日志</summary>
/// <param name="action"></param>
Expand Down
32 changes: 32 additions & 0 deletions NewLife.Remoting.Extensions/RemotingExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Microsoft.Extensions.DependencyInjection.Extensions;
using NewLife.Caching;
using NewLife.Remoting.Extensions.Models;
using NewLife.Remoting.Extensions.Services;
using NewLife.Security;

namespace NewLife.Remoting.Extensions;

/// <summary>远程通信框架扩展</summary>
public static class RemotingExtensions
{
/// <summary>添加远程通信服务端</summary>
/// <param name="services"></param>
/// <param name="setting"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static IServiceCollection AddRemoting(this IServiceCollection services, ITokenSetting setting)
{
if (setting == null) throw new ArgumentNullException(nameof(setting));

// 注册Remoting所必须的服务
services.TryAddSingleton<TokenService>();
services.TryAddSingleton(setting);

// 注册密码提供者,用于通信过程中保护密钥,避免明文传输
services.TryAddSingleton<IPasswordProvider>(new SaltPasswordProvider { Algorithm = "md5", SaltTime = 60 });

services.TryAddSingleton<ICache, MemoryCache>();

return services;
}
}
24 changes: 13 additions & 11 deletions NewLife.Remoting.Extensions/Services/TokenService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

namespace NewLife.Remoting.Extensions.Services;

/// <summary>应用服务</summary>
/// <summary>令牌服务。颁发与验证令牌</summary>
/// <remarks>可重载覆盖功能逻辑</remarks>
public class TokenService
{
/// <summary>颁发令牌</summary>
Expand All @@ -13,7 +14,7 @@ public class TokenService
/// <param name="expire"></param>
/// <param name="id"></param>
/// <returns></returns>
public TokenModel IssueToken(String name, String secret, Int32 expire, String? id = null)
public virtual TokenModel IssueToken(String name, String secret, Int32 expire, String? id = null)
{
if (id.IsNullOrEmpty()) id = Rand.NextString(8);

Expand Down Expand Up @@ -41,11 +42,11 @@ public TokenModel IssueToken(String name, String secret, Int32 expire, String? i

/// <summary>验证并续发新令牌,过期前10分钟才能续发</summary>
/// <param name="name"></param>
/// <param name="token"></param>
/// <param name="secret"></param>
/// <param name="expire"></param>
/// <param name="token"></param>
/// <returns></returns>
public TokenModel? ValidAndIssueToken(String name, String token, String secret, Int32 expire)
public virtual TokenModel? ValidAndIssueToken(String name, String secret, Int32 expire, String token)
{
if (token.IsNullOrEmpty()) return null;

Expand All @@ -63,36 +64,37 @@ public TokenModel IssueToken(String name, String secret, Int32 expire, String? i

/// <summary>解码令牌</summary>
/// <param name="token"></param>
/// <param name="tokenSecret"></param>
/// <param name="secret"></param>
/// <returns></returns>
public (JwtBuilder, Exception?) DecodeTokenWithError(String token, String tokenSecret)
public virtual (JwtBuilder, Exception?) DecodeTokenWithError(String token, String secret)
{
if (token.IsNullOrEmpty()) throw new ArgumentNullException(nameof(token));

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

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

return (jwt, ex);
}

/// <summary>解码令牌,得到App应用</summary>
/// <param name="token"></param>
/// <param name="tokenSecret"></param>
/// <param name="secret"></param>
/// <returns></returns>
public JwtBuilder DecodeToken(String token, String tokenSecret)
public virtual JwtBuilder DecodeToken(String token, String secret)
{
if (token.IsNullOrEmpty()) throw new ArgumentNullException(nameof(token));

// 解码令牌
var ss = tokenSecret.Split(':');
var ss = secret.Split(':');
var jwt = new JwtBuilder
{
Algorithm = ss[0],
Expand Down
23 changes: 21 additions & 2 deletions NewLife.Remoting/Clients/ClientBase.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Net.NetworkInformation;
using System.Reflection;
using System.Security.Cryptography;
using NewLife.Caching;
using NewLife.Log;
using NewLife.Reflection;
Expand Down Expand Up @@ -50,6 +48,9 @@ public abstract class ClientBase : DisposeBase, ICommandClient, IEventProvider,
/// <summary>命令前缀。默认Device/</summary>
public String Prefix { get; set; } = "Device/";

/// <summary>客户端设置</summary>
public IClientSetting? Setting { get; set; }

/// <summary>协议版本</summary>
private String _version;
private TimeSpan _span;
Expand All @@ -64,6 +65,16 @@ public ClientBase()
_version = Assembly.GetExecutingAssembly().GetName().Version + "";
}

/// <summary>通过客户端设置实例化</summary>
/// <param name="setting"></param>
public ClientBase(IClientSetting setting) : this()
{
Setting = setting;

Code = setting.DeviceCode;
Secret = setting.DeviceSecret;
}

/// <summary>销毁</summary>
/// <param name="disposing"></param>
protected override void Dispose(Boolean disposing)
Expand Down Expand Up @@ -164,6 +175,14 @@ protected virtual void SetToken(String? token) { }

OnLogined?.Invoke(this, new(request, rs));

var set = Setting;
if (set != null && !rs.Code.IsNullOrEmpty())
{
set.DeviceCode = rs.Code;
set.DeviceSecret = rs.Secret;
set.Save();
}

StartTimer();

return rs;
Expand Down
2 changes: 2 additions & 0 deletions NewLife.Remoting/Clients/HttpClientBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public HttpClientBase() : base()
/// <param name="urls"></param>
public HttpClientBase(String urls) : this() => AddServices(urls);

public HttpClientBase(IClientSetting setting) : base(setting) => AddServices(setting.Server);

Check warning on line 40 in NewLife.Remoting/Clients/HttpClientBase.cs

View workflow job for this annotation

GitHub Actions / test

Non-nullable field '_client' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.

Check warning on line 40 in NewLife.Remoting/Clients/HttpClientBase.cs

View workflow job for this annotation

GitHub Actions / test

Non-nullable field '_client' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.

Check warning on line 40 in NewLife.Remoting/Clients/HttpClientBase.cs

View workflow job for this annotation

GitHub Actions / build-publish

Non-nullable field '_client' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.

/// <summary>新增服务点</summary>
/// <param name="name"></param>
/// <param name="url"></param>
Expand Down
17 changes: 17 additions & 0 deletions NewLife.Remoting/Clients/IClientSetting.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace NewLife.Remoting.Clients;

/// <summary>客户端设置</summary>
public interface IClientSetting
{
/// <summary>服务端地址。IoT服务平台地址</summary>
String Server { get; set; }

/// <summary>设备证书。在一机一密时手工填写,一型一密时自动下发</summary>
String DeviceCode { get; set; }

/// <summary>设备密钥。在一机一密时手工填写,一型一密时自动下发</summary>
String? DeviceSecret { get; set; }

/// <summary>保存数据</summary>
void Save();
}
3 changes: 2 additions & 1 deletion Samples/IoTZero/Clients/ClientSetting.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System.ComponentModel;
using NewLife.Configuration;
using NewLife.Remoting.Clients;

namespace IoTEdge;

/// <summary>配置</summary>
[Config("IoTClient")]
public class ClientSetting : Config<ClientSetting>
public class ClientSetting : Config<ClientSetting>, IClientSetting
{
#region 属性
/// <summary>服务端地址。IoT服务平台地址</summary>
Expand Down
16 changes: 1 addition & 15 deletions Samples/IoTZero/Clients/HttpDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class HttpDevice : HttpClientBase
#region 构造
public HttpDevice() => Prefix = "Device/";

public HttpDevice(ClientSetting setting) : this()
public HttpDevice(ClientSetting setting) : base(setting)
{
_setting = setting;

Expand All @@ -48,20 +48,6 @@ public override LoginRequest BuildLoginRequest()
//ProductSecret = _setting.DeviceSecret,
};
}

public override async Task<LoginResponse> Login()
{
var rs = await base.Login();

if (Logined && !rs.Secret.IsNullOrEmpty())
{
_setting.DeviceCode = rs.Code;
_setting.DeviceSecret = rs.Secret;
_setting.Save();
}

return rs;
}
#endregion

#region 心跳
Expand Down
14 changes: 6 additions & 8 deletions Samples/IoTZero/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
using IoTZero.Services;
using NewLife.Caching;
using NewLife.Cube;
using NewLife.IoT.Models;
using NewLife.Log;
using NewLife.Reflection;
using NewLife.Remoting.Extensions.Models;
using NewLife.Remoting.Extensions.Services;
using NewLife.Security;
using NewLife.Remoting.Extensions;
using NewLife.Remoting.Models;
using XCode;

// 日志输出到控制台,并拦截全局异常
Expand All @@ -30,12 +30,10 @@
services.AddSingleton<QueueService>();
services.AddSingleton<MyDeviceService>();

// 注册Remoting所必须的服务
services.AddSingleton<TokenService>();
services.AddSingleton<ITokenSetting>(set);
services.AddTransient<LoginRequest, LoginInfo>();

// 注册密码提供者,用于通信过程中保护密钥,避免明文传输
services.AddSingleton<IPasswordProvider>(new SaltPasswordProvider { Algorithm = "md5", SaltTime = 60 });
// 注册Remoting所必须的服务
services.AddRemoting(set);

services.AddHttpClient("hc", e => e.Timeout = TimeSpan.FromSeconds(5));

Expand Down
2 changes: 1 addition & 1 deletion Samples/Zero.RpcServer/Zero.RpcServer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<ItemGroup>
<PackageReference Include="NewLife.Redis" Version="5.7.2024.602" />
<PackageReference Include="NewLife.Stardust" Version="2.9.2024.402" />
<PackageReference Include="NewLife.XCode" Version="11.13.2024.601" />
<PackageReference Include="NewLife.XCode" Version="11.13.2024.606" />
</ItemGroup>

<ItemGroup>
Expand Down

0 comments on commit 1dcb3c1

Please sign in to comment.