feat: 添加加密解密算法,添加upms

main
NoahLan 10 months ago
parent a1c2b29311
commit a213bd1316

@ -46,8 +46,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPin.SqlSugarCore", "src\NP
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "audit-logging", "audit-logging", "{29EA07EB-E1D2-4BCA-9EA4-D69E28F14978}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "audit-logging", "audit-logging", "{29EA07EB-E1D2-4BCA-9EA4-D69E28F14978}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "upms", "upms", "{CA0606BE-4146-4390-86CD-AD92FC161A9E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tenant-management", "tenant-management", "{FFB03EF5-B008-4F84-83D8-2F4B5D821251}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tenant-management", "tenant-management", "{FFB03EF5-B008-4F84-83D8-2F4B5D821251}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPin.Framework.AuditLogging.Domain", "module\audit-logging\NPin.Framework.AuditLogging.Domain\NPin.Framework.AuditLogging.Domain.csproj", "{734EF33E-028A-44C3-B83F-13DBFA8AC117}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPin.Framework.AuditLogging.Domain", "module\audit-logging\NPin.Framework.AuditLogging.Domain\NPin.Framework.AuditLogging.Domain.csproj", "{734EF33E-028A-44C3-B83F-13DBFA8AC117}"
@ -64,6 +62,20 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPin.Framework.TenantManage
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPin.Framework.TenantManagement.SqlSugarCore", "module\tenant-management\NPin.Framework.TenantManagement.SqlSugarCore\NPin.Framework.TenantManagement.SqlSugarCore.csproj", "{9B6CAF84-D53C-4595-93B7-231E771FAED3}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPin.Framework.TenantManagement.SqlSugarCore", "module\tenant-management\NPin.Framework.TenantManagement.SqlSugarCore\NPin.Framework.TenantManagement.SqlSugarCore.csproj", "{9B6CAF84-D53C-4595-93B7-231E771FAED3}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "upms", "upms", "{39C0CC7B-2185-48C6-8D22-F54212CA36D4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "code-gen", "code-gen", "{0FBD3B80-E61E-4797-9599-98E8884E5798}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPin.Framework.Upms.Domain.Shared", "module\upms\NPin.Framework.Upms.Domain.Shared\NPin.Framework.Upms.Domain.Shared.csproj", "{23E194C3-B1E2-49C9-A145-DFD3CDE724AD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPin.Framework.Upms.Domain", "module\upms\NPin.Framework.Upms.Domain\NPin.Framework.Upms.Domain.csproj", "{C159A479-5020-4E8D-9377-6E2F6EA06396}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPin.Framework.Upms.SqlSugarCore", "module\upms\NPin.Framework.Upms.SqlSugarCore\NPin.Framework.Upms.SqlSugarCore.csproj", "{786A1422-C4BD-4742-B33D-EBB82762CC63}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPin.Framework.Upms.Application.Contracts", "module\upms\NPin.Framework.Upms.Application.Contracts\NPin.Framework.Upms.Application.Contracts.csproj", "{028A9FD0-3C94-45D6-9A4D-68BD4985B176}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPin.Framework.Upms.Application", "module\upms\NPin.Framework.Upms.Application\NPin.Framework.Upms.Application.csproj", "{A48B3BDD-5996-438B-951A-09C52E595FCB}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -158,6 +170,26 @@ Global
{9B6CAF84-D53C-4595-93B7-231E771FAED3}.Debug|Any CPU.Build.0 = Debug|Any CPU {9B6CAF84-D53C-4595-93B7-231E771FAED3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9B6CAF84-D53C-4595-93B7-231E771FAED3}.Release|Any CPU.ActiveCfg = Release|Any CPU {9B6CAF84-D53C-4595-93B7-231E771FAED3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9B6CAF84-D53C-4595-93B7-231E771FAED3}.Release|Any CPU.Build.0 = Release|Any CPU {9B6CAF84-D53C-4595-93B7-231E771FAED3}.Release|Any CPU.Build.0 = Release|Any CPU
{23E194C3-B1E2-49C9-A145-DFD3CDE724AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{23E194C3-B1E2-49C9-A145-DFD3CDE724AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{23E194C3-B1E2-49C9-A145-DFD3CDE724AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{23E194C3-B1E2-49C9-A145-DFD3CDE724AD}.Release|Any CPU.Build.0 = Release|Any CPU
{C159A479-5020-4E8D-9377-6E2F6EA06396}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C159A479-5020-4E8D-9377-6E2F6EA06396}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C159A479-5020-4E8D-9377-6E2F6EA06396}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C159A479-5020-4E8D-9377-6E2F6EA06396}.Release|Any CPU.Build.0 = Release|Any CPU
{786A1422-C4BD-4742-B33D-EBB82762CC63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{786A1422-C4BD-4742-B33D-EBB82762CC63}.Debug|Any CPU.Build.0 = Debug|Any CPU
{786A1422-C4BD-4742-B33D-EBB82762CC63}.Release|Any CPU.ActiveCfg = Release|Any CPU
{786A1422-C4BD-4742-B33D-EBB82762CC63}.Release|Any CPU.Build.0 = Release|Any CPU
{028A9FD0-3C94-45D6-9A4D-68BD4985B176}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{028A9FD0-3C94-45D6-9A4D-68BD4985B176}.Debug|Any CPU.Build.0 = Debug|Any CPU
{028A9FD0-3C94-45D6-9A4D-68BD4985B176}.Release|Any CPU.ActiveCfg = Release|Any CPU
{028A9FD0-3C94-45D6-9A4D-68BD4985B176}.Release|Any CPU.Build.0 = Release|Any CPU
{A48B3BDD-5996-438B-951A-09C52E595FCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A48B3BDD-5996-438B-951A-09C52E595FCB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A48B3BDD-5996-438B-951A-09C52E595FCB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A48B3BDD-5996-438B-951A-09C52E595FCB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{088B4948-AE5B-45B3-A9FA-B853671CFA05} = {F2A0A89E-A2F9-48CF-AD38-0318B5ACD11C} {088B4948-AE5B-45B3-A9FA-B853671CFA05} = {F2A0A89E-A2F9-48CF-AD38-0318B5ACD11C}
@ -176,7 +208,6 @@ Global
{C4D324BB-01B6-436F-9AA6-136C7D5438F6} = {86F61EBB-4ACC-459C-AB3C-C8D486C3017D} {C4D324BB-01B6-436F-9AA6-136C7D5438F6} = {86F61EBB-4ACC-459C-AB3C-C8D486C3017D}
{DC8E2E59-589F-4521-95E2-9CE7E1DD5541} = {86F61EBB-4ACC-459C-AB3C-C8D486C3017D} {DC8E2E59-589F-4521-95E2-9CE7E1DD5541} = {86F61EBB-4ACC-459C-AB3C-C8D486C3017D}
{29EA07EB-E1D2-4BCA-9EA4-D69E28F14978} = {EEAD0AD4-0F90-46D9-A775-D88AE07E2869} {29EA07EB-E1D2-4BCA-9EA4-D69E28F14978} = {EEAD0AD4-0F90-46D9-A775-D88AE07E2869}
{CA0606BE-4146-4390-86CD-AD92FC161A9E} = {EEAD0AD4-0F90-46D9-A775-D88AE07E2869}
{FFB03EF5-B008-4F84-83D8-2F4B5D821251} = {EEAD0AD4-0F90-46D9-A775-D88AE07E2869} {FFB03EF5-B008-4F84-83D8-2F4B5D821251} = {EEAD0AD4-0F90-46D9-A775-D88AE07E2869}
{734EF33E-028A-44C3-B83F-13DBFA8AC117} = {29EA07EB-E1D2-4BCA-9EA4-D69E28F14978} {734EF33E-028A-44C3-B83F-13DBFA8AC117} = {29EA07EB-E1D2-4BCA-9EA4-D69E28F14978}
{70685213-B0C0-4589-B9ED-A67838227705} = {29EA07EB-E1D2-4BCA-9EA4-D69E28F14978} {70685213-B0C0-4589-B9ED-A67838227705} = {29EA07EB-E1D2-4BCA-9EA4-D69E28F14978}
@ -185,5 +216,12 @@ Global
{FAB3D7AE-2260-4DC1-B2BB-E26C540056BF} = {FFB03EF5-B008-4F84-83D8-2F4B5D821251} {FAB3D7AE-2260-4DC1-B2BB-E26C540056BF} = {FFB03EF5-B008-4F84-83D8-2F4B5D821251}
{6F3DF341-F4BB-416A-8772-F68B4626C0C8} = {FFB03EF5-B008-4F84-83D8-2F4B5D821251} {6F3DF341-F4BB-416A-8772-F68B4626C0C8} = {FFB03EF5-B008-4F84-83D8-2F4B5D821251}
{9B6CAF84-D53C-4595-93B7-231E771FAED3} = {FFB03EF5-B008-4F84-83D8-2F4B5D821251} {9B6CAF84-D53C-4595-93B7-231E771FAED3} = {FFB03EF5-B008-4F84-83D8-2F4B5D821251}
{39C0CC7B-2185-48C6-8D22-F54212CA36D4} = {EEAD0AD4-0F90-46D9-A775-D88AE07E2869}
{0FBD3B80-E61E-4797-9599-98E8884E5798} = {EEAD0AD4-0F90-46D9-A775-D88AE07E2869}
{23E194C3-B1E2-49C9-A145-DFD3CDE724AD} = {39C0CC7B-2185-48C6-8D22-F54212CA36D4}
{C159A479-5020-4E8D-9377-6E2F6EA06396} = {39C0CC7B-2185-48C6-8D22-F54212CA36D4}
{786A1422-C4BD-4742-B33D-EBB82762CC63} = {39C0CC7B-2185-48C6-8D22-F54212CA36D4}
{028A9FD0-3C94-45D6-9A4D-68BD4985B176} = {39C0CC7B-2185-48C6-8D22-F54212CA36D4}
{A48B3BDD-5996-438B-951A-09C52E595FCB} = {39C0CC7B-2185-48C6-8D22-F54212CA36D4}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

@ -0,0 +1,84 @@
using System.Security.Cryptography;
using System.Text;
namespace NPin.Framework.Core.Crypt.AES;
public static class AesCrypt
{
/// <summary>
/// 盐
/// </summary>
private const string Slat = "Q+OFqu]luparUP;Xn^_ktHX^FoWiK4C#;daRV(b1bbT_;HrrAL";
/// <summary>
/// 处理key
/// </summary>
/// <param name="pwd">输入的密码</param>
/// <param name="model">Key和IV模式</param>
/// <returns></returns>
private static Tuple<byte[], byte[]> GetAesKey(string pwd, AesKeyEnum model = AesKeyEnum.AES256)
{
var hash1 = $"{pwd}-{Slat}".Md5();
switch (model)
{
case AesKeyEnum.AES256:
{
var hash2 = $"{hash1}-{Slat}".Md5();
var hash3 = $"{hash2}-{Slat}".To16Md5();
var key = Encoding.UTF8.GetBytes($"{hash1}{hash2}".Md5());
var iv = Encoding.UTF8.GetBytes(hash3);
return new(key, iv);
}
case AesKeyEnum.AES128:
{
var hash2 = $"{hash1}-{Slat}".To16Md5();
var key = Encoding.UTF8.GetBytes(hash1);
var iv = Encoding.UTF8.GetBytes(hash2);
return new(key, iv);
}
default: throw new("不支持的类型");
}
}
/// <summary>
/// AES加密
/// </summary>
/// <param name="content">待加密数据</param>
/// <param name="pwd">密钥</param>
/// <param name="model">Aes密钥模式</param>
/// <param name="mode">加密模式</param>
/// <param name="padding">填充模式</param>
/// <returns></returns>
public static byte[] Encrypt(byte[] content, string pwd, AesKeyEnum model, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
{
var (Key, IV) = GetAesKey(pwd, model);
using var aes = Aes.Create();
aes.Key = Key;
aes.IV = IV;
aes.Mode = mode;
aes.Padding = padding;
var cTransform = aes.CreateEncryptor();
return cTransform.TransformFinalBlock(content, 0, content.Length);
}
/// <summary>
/// AES解密
/// </summary>
/// <param name="secret">待解密数据</param>
/// <param name="pwd">密钥</param>
/// <param name="model">Aes密钥模式</param>
/// <param name="mode">加密模式</param>
/// <param name="padding">填充模式</param>
/// <returns></returns>
public static byte[] Decrypt(byte[] secret, string pwd, AesKeyEnum model, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
{
var (key, iv) = GetAesKey(pwd, model);
using var aes = Aes.Create();
aes.Key = key;
aes.IV = iv;
aes.Mode = mode;
aes.Padding = padding;
var cTransform = aes.CreateDecryptor();
return cTransform.TransformFinalBlock(secret, 0, secret.Length);
}
}

@ -0,0 +1,17 @@
namespace NPin.Framework.Core.Crypt.AES;
/// <summary>
/// AES加密的密钥算法模式
/// </summary>
public enum AesKeyEnum
{
/// <summary>
/// AES128
/// </summary>
AES128,
/// <summary>
/// AES256
/// </summary>
AES256
}

@ -0,0 +1,14 @@
using System.Text;
namespace NPin.Framework.Core.Crypt.BCrypt;
public static class BCrypt
{
public static byte[] Generate(string password, string salt, int cost)
{
var passBytes = Encoding.UTF8.GetBytes(password);
var saltBytes = Encoding.UTF8.GetBytes(salt);
return Org.BouncyCastle.Crypto.Generators.BCrypt.Generate(passBytes, saltBytes, cost);
}
}

@ -0,0 +1,77 @@
using System.Security.Cryptography;
using System.Text;
namespace NPin.Framework.Core.Crypt.DES;
/// <summary>
/// DES加密解密(由于本库对密钥进行了hash算法处理.使用本库加密仅能用本库解密)
/// </summary>
public static class DesCrypt
{
/// <summary>
/// 盐
/// </summary>
private const string Slat = "Fo~@Ymf3w-!K+hYYoI^emXJeNt79pv@Sy,rpl0vXyIa-^jI{fU";
/// <summary>
/// 处理key
/// </summary>
/// <param name="pwd">输入的密码</param>
/// <returns></returns>
private static Tuple<byte[], byte[]> GetEesKey(string pwd)
{
var hash1 = $"{pwd}-{Slat}".Md5();
var hash2 = $"{hash1}-{Slat}".Md5();
var hash3 = $"{hash2}-{Slat}".To16Md5();
var key = Encoding.UTF8.GetBytes($"{hash1}{hash2}".To16Md5()[..8]);
var iv = Encoding.UTF8.GetBytes(hash3[..8]);
return new(key, iv);
}
/// <summary>
/// DES加密
/// </summary>
/// <param name="content">待加密数据</param>
/// <param name="pwd">密钥</param>
/// <param name="mode">加密模式</param>
/// <param name="padding">填充模式</param>
/// <returns>加密后的数据</returns>
public static byte[] Encrypt(byte[] content, string pwd, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
{
var (key, iv) = GetEesKey(pwd);
var des = System.Security.Cryptography.DES.Create();
des.Key = key;
des.IV = iv;
des.Mode = mode;
des.Padding = padding;
using var ms = new MemoryStream();
using var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(content, 0, content.Length);
cs.FlushFinalBlock();
return ms.ToArray();
}
/// <summary>
/// DES解密字符串
/// </summary>
/// <param name="secret">待解密数据</param>
/// <param name="pwd">密钥</param>
/// <param name="mode">加密模式</param>
/// <param name="padding">填充模式</param>
/// <returns>解密后的字符串</returns>
public static byte[] Decrypt(byte[] secret, string pwd, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
{
var (key, iv) = GetEesKey(pwd);
var des = System.Security.Cryptography.DES.Create();
des.Key = key;
des.IV = iv;
des.Mode = mode;
des.Padding = padding;
using var ms = new MemoryStream();
using var cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
cs.Write(secret, 0, secret.Length);
cs.FlushFinalBlock();
return ms.ToArray();
}
}

@ -0,0 +1,73 @@
using System.Security.Cryptography;
using System.Text;
namespace NPin.Framework.Core.Crypt.DES;
public static class TripleDes
{
/// <summary>
/// 盐
/// </summary>
private const string slat = "HosW[A1]ew0sVtVzf[DfQ~x%hk2+ifMlg;)Wsf[9@Fh{_z$jNC";
/// <summary>
/// 处理key
/// </summary>
/// <param name="pwd">输入的密码</param>
/// <returns></returns>
private static Tuple<byte[], byte[]> GetEesKey(string pwd)
{
var hash1 = $"{pwd}-{slat}".Md5();
var hash2 = $"{hash1}-{slat}".Md5();
var hash3 = $"{hash2}-{slat}".To16Md5();
var Key = Encoding.UTF8.GetBytes($"{hash1}{hash2}".Md5()[..24]);
var IV = Encoding.UTF8.GetBytes(hash3[..8]);
return new(Key, IV);
}
/// <summary>
/// 使用给定密钥加密
/// </summary>
/// <param name="content">待加密数据</param>
/// <param name="pwd">密钥</param>
/// <param name="mode">加密模式</param>
/// <param name="padding">填充模式</param>
/// <returns>加密后的数据</returns>
public static byte[] Encrypt(byte[] content, string pwd, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
{
var (Key, IV) = GetEesKey(pwd);
var des = TripleDES.Create();
des.Key = Key;
des.IV = IV;
des.Mode = mode;
des.Padding = padding;
using var ms = new MemoryStream();
using var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(content, 0, content.Length);
cs.FlushFinalBlock();
return ms.ToArray();
}
/// <summary>
/// 使用给定密钥解密数据
/// </summary>
/// <param name="secret">待解密数据</param>
/// <param name="pwd">密钥</param>
/// <param name="mode">加密模式</param>
/// <param name="padding">填充模式</param>
/// <returns>解密后的数据</returns>
public static byte[] Decrypt(byte[] secret, string pwd, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
{
var (Key, IV) = GetEesKey(pwd);
var des = TripleDES.Create();
des.Key = Key;
des.IV = IV;
des.Mode = mode;
des.Padding = padding;
using var ms = new MemoryStream();
using var cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
cs.Write(secret, 0, secret.Length);
cs.FlushFinalBlock();
return ms.ToArray();
}
}

@ -0,0 +1,36 @@
using System.Security.Cryptography;
using System.Text;
namespace NPin.Framework.Core.Crypt;
public static class Md5Extensions
{
/// <summary>
/// 获取16位长度的MD5大写字符串
/// 截取第 9~25 位
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static string To16Md5(this string value) => value.Md5().Substring(8, 16);
/// <summary>
/// 获取32位长度的MD5大写字符串
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static string Md5(this string value)
{
using var md5 = MD5.Create();
var inputBytes = Encoding.UTF8.GetBytes(value);
var hashBytes = md5.ComputeHash(inputBytes);
var sb = new StringBuilder();
foreach (var hash in hashBytes)
{
sb.Append(hash.ToString("X2"));
}
return sb.ToString();
}
}

@ -0,0 +1,48 @@
namespace NPin.Framework.Core.Crypt.RC4;
/// <summary>
/// RC4 加密解密
/// </summary>
public static class Rc4Crypt
{
/// <summary>
/// RC4解密
/// </summary>
/// <param name="data">待解密数据</param>
/// <param name="key">密钥</param>
/// <returns></returns>
public static byte[] Decrypt(IEnumerable<byte> data, byte[] key) => Encrypt(data, key);
/// <summary>
/// RC4加密
/// </summary>
/// <param name="data">待加密数据</param>
/// <param name="key">密钥</param>
/// <returns></returns>
public static byte[] Encrypt(IEnumerable<byte> data, byte[] key)
{
var s = EncryptInit(key);
var i = 0;
var j = 0;
return data.Select(b =>
{
i = (i + 1) & 255;
j = (j + s[i]) & 255;
Swap(s, i, j);
return (byte)(b ^ s[(s[i] + s[j]) & 255]);
}).ToArray();
}
private static byte[] EncryptInit(byte[] key)
{
var s = Enumerable.Range(0, 256).Select(i => (byte)i).ToArray();
for (int i = 0, j = 0; i < 256; i++)
{
j = (j + key[i % key.Length] + s[i]) & 255;
Swap(s, i, j);
}
return s;
}
private static void Swap(byte[] s, int i, int j) => (s[i], s[j]) = (s[j], s[i]);
}

@ -0,0 +1,14 @@
> 来自于[EasilyNET.Security](https://github.com/EasilyNET/EasilyNET/blob/main/src/EasilyNET.Security/README.md)的加密库封装
一个.Net 中常用的加密算法的封装.降低加密解密的使用复杂度.
- 目前有的算法:AES,DES,RC4,TripleDES,RSA,SM2,SM3,SM4
- 支持 RSA XML 结构的 SecurityKey 和 Base64 格式的互转.
- 本库不是去实现加密算法,而是基于.Net 提供的接口封装,为了方便使用
- 未经测试的预测,若是遇到了解密乱码,可能是需要引入一个包.
- 在主项目中添加 System.Text.Encoding.CodePages 库,并在程序入口处添加注册代码. Programe.cs
```c#
var builder = WebApplication.CreateBuilder(args);
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
```

@ -0,0 +1,178 @@
using System.Security.Cryptography;
using System.Text;
namespace NPin.Framework.Core.Crypt.RSA;
/// <summary>
/// RSA算法
/// </summary>
public static class RsaCrypt
{
/// <summary>
/// 创建RSA密钥对
/// </summary>
/// <param name="keySize">密钥的大小,必须384位到16384位,增量为8</param>
/// <returns></returns>
public static RsaSecretKey GenerateKey(int keySize)
{
if (keySize is > 16384 or < 384 && keySize % 8 is not 0)
{
throw new ArgumentException("密钥的大小,必须384位到16384位,增量为8", nameof(keySize));
}
var rsa = new RSACryptoServiceProvider(keySize)
{
KeySize = keySize,
PersistKeyInCsp = false
};
return new()
{
PrivateKey = rsa.ToXmlString(true),
PublicKey = rsa.ToXmlString(false)
};
}
/// <summary>
/// 创建RSA密钥对
/// </summary>
/// <param name="keySize">密钥的大小,提供常用长度枚举</param>
/// <returns></returns>
public static RsaSecretKey GenerateKey(RsaKeyLength keySize) => GenerateKey((int)keySize);
/// <summary>
/// 使用RSA的加密byte[](该方法存在长度限制)
/// </summary>
/// <param name="xmlPublicKey">当前RSA对象的密匙XML字符串(不包括专用参数)--公钥</param>
/// <param name="content">需要进行加密的字节数组</param>
/// <returns>加密后的数据</returns>
public static byte[] Encrypt(string xmlPublicKey, byte[] content)
{
using var rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(xmlPublicKey);
return rsa.Encrypt(content, false);
}
/// <summary>
/// RSA解密byte[](该方法存在长度限制)
/// </summary>
/// <param name="xmlPrivateKey">当前RSA对象的密匙XML字符串(包括专用参数)--私钥</param>
/// <param name="secret">需要进行解密的字节数组</param>
/// <returns>解密后的字符串</returns>
public static byte[] Decrypt(string xmlPrivateKey, byte[] secret)
{
using var rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(xmlPrivateKey);
return rsa.Decrypt(secret, false);
}
/// <summary>
/// RSA加密 不限长度的加密版本
/// </summary>
/// <param name="xmlPublicKey">公匙</param>
/// <param name="content">需要进行加密的数据</param>
/// <param name="secret">加密后的数据</param>
public static void Encrypt(string xmlPublicKey, byte[] content, out byte[] secret)
{
if (content.Length is 0) throw new("加密字符串不能为空.");
ArgumentException.ThrowIfNullOrEmpty(xmlPublicKey, nameof(xmlPublicKey));
using var rsaProvider = new RSACryptoServiceProvider();
rsaProvider.FromXmlString(xmlPublicKey); //载入公钥
var bufferSize = (rsaProvider.KeySize >> 3) - 11; //单块最大长度
var buffer = new byte[bufferSize];
using MemoryStream ms = new(content), os = new();
while (true)
{
//分段加密
var readSize = ms.Read(buffer, 0, bufferSize);
if (readSize <= 0) break;
var temp = new byte[readSize];
Array.Copy(buffer, 0, temp, 0, readSize);
var encryptedBytes = rsaProvider.Encrypt(temp, false);
os.Write(encryptedBytes, 0, encryptedBytes.Length);
}
secret = os.ToArray(); //转化为字节流方便传输
}
/// <summary>
/// RSA解密 不限长度的解密版本
/// </summary>
/// <param name="xmlPrivateKey">私匙</param>
/// <param name="secret">需要进行解密的数据</param>
/// <param name="context">解密后的数据</param>
public static void Decrypt(string xmlPrivateKey, byte[] secret, out byte[] context)
{
if (secret.Length is 0) throw new("解密字符串不能为空.");
ArgumentException.ThrowIfNullOrEmpty(xmlPrivateKey, nameof(xmlPrivateKey));
using var rsaProvider = new RSACryptoServiceProvider();
rsaProvider.FromXmlString(xmlPrivateKey);
var bufferSize = rsaProvider.KeySize >> 3;
var buffer = new byte[bufferSize];
using MemoryStream ms = new(secret), os = new();
while (true)
{
var readSize = ms.Read(buffer, 0, bufferSize);
if (readSize <= 0) break;
var temp = new byte[readSize];
Array.Copy(buffer, 0, temp, 0, readSize);
var rawBytes = rsaProvider.Decrypt(temp, false);
os.Write(rawBytes, 0, rawBytes.Length);
}
context = os.ToArray();
}
/// <summary>
/// 从文件中取得SHA256描述信息
/// </summary>
/// <param name="objFile"></param>
/// <returns></returns>
public static string GetFileSHA256(FileStream objFile)
{
ArgumentNullException.ThrowIfNull(objFile, nameof(objFile));
using var stream = new MemoryStream();
objFile.CopyTo(stream);
var bytes = stream.ToArray();
var array = SHA256.HashData(bytes);
objFile.Close();
return Encoding.UTF8.GetString(array);
}
#region RSA签名与签名验证
/// <summary>
/// RSA签名
/// </summary>
/// <param name="xmlPrivateKey">当前RSA对象的密匙XML字符串(包括专用参数)--私钥</param>
/// <param name="context">需要签名的数据</param>
/// <returns>签名数据</returns>
public static byte[] Signature(string xmlPrivateKey, byte[] context)
{
using var rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(xmlPrivateKey);
var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa);
//设置签名的算法为SHA256
rsaFormatter.SetHashAlgorithm("SHA256");
//执行签名
return rsaFormatter.CreateSignature(context);
}
/// <summary>
/// RSA 签名验证
/// </summary>
/// <param name="xmlPublicKey">当前RSA对象的密匙XML字符串(不包括专用参数)--公钥</param>
/// <param name="secret">用RSA签名的数据[俗称:Hash描述字符串,即:MD5或者SHA256这种.本库使用SHA256]</param>
/// <param name="signature">要为该数据验证的已签名数据</param>
/// <returns>如果 Verification 与使用指定的哈希算法和密钥在 signature 上计算出的签名匹配,则为 <see langword="true" />;否则为 <see langword="false" />.</returns>
public static bool Verification(string xmlPublicKey, byte[] secret, byte[] signature)
{
using var rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(xmlPublicKey);
var formatter = new RSAPKCS1SignatureDeformatter(rsa);
//指定解密的时候HASH算法为SHA256
formatter.SetHashAlgorithm("SHA256");
return formatter.VerifySignature(secret, signature);
}
#endregion
}

@ -0,0 +1,89 @@
using System.Security.Cryptography;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.X509;
namespace NPin.Framework.Core.Crypt.RSA;
/// <summary>
/// RSAKey转化扩展类,用于将XML格式和Base64这种互转.如C#和Java的编码就不一样.
/// </summary>
public static class RsaKeyConverter
{
/// <summary>
/// XML私钥 👉 Base64私钥
/// </summary>
/// <param name="xmlPrivate">XML私钥</param>
/// <returns>Base64私钥</returns>
public static string ToBase64PrivateKey(string xmlPrivate)
{
using var rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(xmlPrivate);
var param = rsa.ExportParameters(true);
var privateKeyParam = new RsaPrivateCrtKeyParameters(new(1, param.Modulus), new(1, param.Exponent),
new(1, param.D), new(1, param.P),
new(1, param.Q), new(1, param.DP),
new(1, param.DQ), new(1, param.InverseQ));
var privateKey = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKeyParam);
return Convert.ToBase64String(privateKey.ToAsn1Object().GetEncoded());
}
/// <summary>
/// XML公钥 👉 Base64公钥
/// </summary>
/// <param name="xmlPublic">XML公钥</param>
/// <returns>Base64公钥</returns>
public static string ToBase64PublicKey(string xmlPublic)
{
using var rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(xmlPublic);
var p = rsa.ExportParameters(false);
var keyParams = new RsaKeyParameters(false, new(1, p.Modulus), new(1, p.Exponent));
var publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyParams);
return Convert.ToBase64String(publicKeyInfo.ToAsn1Object().GetEncoded());
}
/// <summary>
/// Base64私钥 👉 XML私钥
/// </summary>
/// <param name="base64Private">Base64私钥</param>
/// <returns>XML私钥</returns>
public static string ToXmlPrivateKey(string base64Private)
{
var privateKeyParams =
(RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(base64Private));
using var rsa = new RSACryptoServiceProvider();
var rsaParams = new RSAParameters
{
Modulus = privateKeyParams.Modulus.ToByteArrayUnsigned(),
Exponent = privateKeyParams.PublicExponent.ToByteArrayUnsigned(),
D = privateKeyParams.Exponent.ToByteArrayUnsigned(),
DP = privateKeyParams.DP.ToByteArrayUnsigned(),
DQ = privateKeyParams.DQ.ToByteArrayUnsigned(),
P = privateKeyParams.P.ToByteArrayUnsigned(),
Q = privateKeyParams.Q.ToByteArrayUnsigned(),
InverseQ = privateKeyParams.QInv.ToByteArrayUnsigned()
};
rsa.ImportParameters(rsaParams);
return rsa.ToXmlString(true);
}
/// <summary>
/// Base64公钥 👉 XML公钥
/// </summary>
/// <param name="base64Public">Base64公钥</param>
/// <returns>XML公钥</returns>
public static string ToXmlPublicKey(string base64Public)
{
var p = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(base64Public));
using var rsa = new RSACryptoServiceProvider();
var rsaParams = new RSAParameters
{
Modulus = p.Modulus.ToByteArrayUnsigned(),
Exponent = p.Exponent.ToByteArrayUnsigned()
};
rsa.ImportParameters(rsaParams);
return rsa.ToXmlString(false);
}
}

@ -0,0 +1,27 @@
namespace NPin.Framework.Core.Crypt.RSA;
/// <summary>
/// RSA 密钥长度
/// </summary>
public enum RsaKeyLength
{
/// <summary>
/// 512 bit
/// </summary>
Bit512 = 512,
/// <summary>
/// 1024 bit
/// </summary>
Bit1024 = 1024,
/// <summary>
/// 2048 bit
/// </summary>
Bit2048 = 2048,
/// <summary>
/// 4096 bit
/// </summary>
Bit4096 = 4096
}

@ -0,0 +1,49 @@
namespace NPin.Framework.Core.Crypt.RSA;
/// <summary>
/// RSA密钥 结构体
/// </summary>
/// <param name="privateKey"></param>
/// <param name="publicKey"></param>
public struct RsaSecretKey(string privateKey, string publicKey)
{
/// <summary>
/// 公钥
/// </summary>
public string PublicKey { get; set; } = publicKey;
/// <summary>
/// 私钥
/// </summary>
public string PrivateKey { get; set; } = privateKey;
/// <summary>
/// 得到XML格式的私钥和公钥
/// </summary>
/// <returns></returns>
public readonly string ToXmlString() =>
$"""
-----BEGIN RSA XML PRIVATE KEY-----
{PrivateKey}
-----END RSA XML PRIVATE KEY-----
-----BEGIN RSA XML PUBLIC KEY-----
{PublicKey}
-----END RSA XML PUBLIC KEY-----
""";
/// <summary>
/// 得到Base64格式的私钥和公钥
/// </summary>
/// <returns></returns>
public readonly string ToBase64String() =>
$"""
-----BEGIN RSA BASE64 PRIVATE KEY-----
{RsaKeyConverter.ToBase64PrivateKey(PrivateKey)}
-----END RSA BASE64 PRIVATE KEY-----
-----BEGIN RSA BASE64 PUBLIC KEY-----
{RsaKeyConverter.ToBase64PublicKey(PublicKey)}
-----END RSA BASE64 PUBLIC KEY-----
""";
}

@ -0,0 +1,157 @@
using Org.BouncyCastle.Asn1.GM;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
namespace NPin.Framework.Core.Crypt.SM2;
/// <summary>
/// BouncyCastle(BC) 实现SM2国密加解密、签名、验签
/// </summary>
public static class Sm2Crypt
{
private static readonly X9ECParameters X9 = GMNamedCurves.GetByName("SM2P256V1");
/// <summary>
/// 构建公钥和私钥
/// </summary>
/// <param name="publicKey"></param>
/// <param name="privateKey"></param>
public static void GenerateKey(out byte[] publicKey, out byte[] privateKey)
{
var g = new ECKeyPairGenerator();
g.Init(new ECKeyGenerationParameters(new ECDomainParameters(X9), new()));
var k = g.GenerateKeyPair();
publicKey = ((ECPublicKeyParameters)k.Public).Q.GetEncoded(false);
privateKey = ((ECPrivateKeyParameters)k.Private).D.ToByteArray();
}
/// <summary>
/// SM2加密,默认:C1C3C2
/// </summary>
/// <param name="publicKey">公钥</param>
/// <param name="data">需要加密的数据</param>
/// <param name="model">模式</param>
/// <param name="userId">用户ID</param>
/// <returns></returns>
public static byte[] Encrypt(byte[] publicKey, byte[] data, byte[]? userId = null,
SM2Engine.Mode model = SM2Engine.Mode.C1C3C2)
{
var sm2 = new SM2Engine(new SM3Digest(), SM2Engine.Mode.C1C3C2);
ICipherParameters cp =
new ParametersWithRandom(new ECPublicKeyParameters(X9.Curve.DecodePoint(publicKey), new(X9)));
if (userId is not null)
{
cp = new ParametersWithID(cp, userId);
}
sm2.Init(true, cp);
data = sm2.ProcessBlock(data, 0, data.Length);
if (model == SM2Engine.Mode.C1C2C3) data = C132ToC123(data);
return data;
}
/// <summary>
/// SM2解密,默认:C1C3C2
/// </summary>
/// <param name="privateKey">私钥</param>
/// <param name="data">需要解密的数据</param>
/// <param name="model">模式</param>
/// <param name="userId">用户ID</param>
/// <returns></returns>
public static byte[] Decrypt(byte[] privateKey, byte[] data, byte[]? userId = null,
SM2Engine.Mode model = SM2Engine.Mode.C1C3C2)
{
if (model == SM2Engine.Mode.C1C2C3) data = C123ToC132(data);
var sm2 = new SM2Engine(new SM3Digest(), SM2Engine.Mode.C1C3C2);
ICipherParameters cp = new ECPrivateKeyParameters(new(1, privateKey), new(X9));
if (userId is not null)
{
cp = new ParametersWithID(cp, userId);
}
sm2.Init(false, cp);
return sm2.ProcessBlock(data, 0, data.Length);
}
/// <summary>
/// SM2签名
/// </summary>
/// <param name="privateKey">私钥</param>
/// <param name="msg">数据</param>
/// <param name="userId">用户ID</param>
/// <returns></returns>
public static byte[] Signature(byte[] privateKey, byte[] msg, byte[]? userId = null)
{
var sm2 = new SM2Signer(new SM3Digest());
// var sm2 = new SM2Signer(StandardDsaEncoding.Instance, new SM3Digest());
// var sm2 = new SM2Signer(PlainDsaEncoding.Instance, new SM3Digest());
ICipherParameters cp = new ParametersWithRandom(new ECPrivateKeyParameters(new(1, privateKey), new(X9)));
if (userId is not null)
{
cp = new ParametersWithID(cp, userId);
}
sm2.Init(true, cp);
sm2.BlockUpdate(msg, 0, msg.Length);
return sm2.GenerateSignature();
}
/// <summary>
/// SM2验签
/// </summary>
/// <param name="publicKey">公钥</param>
/// <param name="msg">数据</param>
/// <param name="signature">签名数据</param>
/// <param name="userId">用户ID</param>
/// <returns></returns>
public static bool Verify(byte[] publicKey, byte[] msg, byte[] signature, byte[]? userId = null)
{
var sm2 = new SM2Signer(new SM3Digest());
ICipherParameters cp = new ECPublicKeyParameters(X9.Curve.DecodePoint(publicKey), new(X9));
if (userId is not null)
{
cp = new ParametersWithID(cp, userId);
}
sm2.Init(false, cp);
sm2.BlockUpdate(msg, 0, msg.Length);
return sm2.VerifySignature(signature);
}
/// <summary>
/// C1C2C3转成C1C3C2
/// </summary>
/// <param name="c1c2c3"></param>
/// <returns></returns>
private static byte[] C123ToC132(byte[] c1c2c3)
{
var c1Len = (((X9.Curve.FieldSize + 7) >> 3) << 1) + 1; //sm2p256v1的这个固定65。可看GMNamedCurves、ECCurve代码。
const int c3Len = 32;
var result = new byte[c1c2c3.Length];
Array.Copy(c1c2c3, 0, result, 0, c1Len); //c1
Array.Copy(c1c2c3, c1c2c3.Length - c3Len, result, c1Len, c3Len); //c3
Array.Copy(c1c2c3, c1Len, result, c1Len + c3Len, c1c2c3.Length - c1Len - c3Len); //c2
return result;
}
/// <summary>
/// C1C3C2转成C1C2C3
/// </summary>
/// <param name="c1c3c2"></param>
/// <returns></returns>
private static byte[] C132ToC123(byte[] c1c3c2)
{
var c1Len = (((X9.Curve.FieldSize + 7) >> 3) << 1) + 1;
const int c3Len = 32;
var result = new byte[c1c3c2.Length];
Array.Copy(c1c3c2, 0, result, 0, c1Len); //c1: 0->65
Array.Copy(c1c3c2, c1Len + c3Len, result, c1Len, c1c3c2.Length - c1Len - c3Len); //c2
Array.Copy(c1c3c2, c1Len, result, c1c3c2.Length - c3Len, c3Len); //c3
return result;
}
}

@ -0,0 +1,37 @@
using System.Text;
using Org.BouncyCastle.Crypto.Digests;
namespace NPin.Framework.Core.Crypt.SM3;
/// <summary>
/// SM3算法(10进制的ASCII)
/// 在SHA-256基础上改进实现的一种算法
/// 对标国际MD5算法和SHA算法
/// </summary>
public static class Sm3Crypt
{
/// <summary>
/// 获取字符串的SM3签名
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static byte[] Signature(string data)
{
var msg = Encoding.UTF8.GetBytes(data);
return Signature(msg);
}
/// <summary>
/// 获取字节数组的SM3签名
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static byte[] Signature(byte[] data)
{
var md = new byte[32];
var sm3 = new SM3Digest();
sm3.BlockUpdate(data, 0, data.Length);
sm3.DoFinal(md, 0);
return md;
}
}

@ -0,0 +1,323 @@
namespace NPin.Framework.Core.Crypt.SM4;
internal sealed class Sm4
{
/// <summary>
/// 固定参数CK
/// </summary>
private readonly uint[] CK =
[
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
];
/// <summary>
/// 系统参数FK
/// </summary>
private readonly uint[] FK = [0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc];
/// <summary>
/// S盒
/// </summary>
private readonly byte[] SBoxTable =
[
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f*/
/*0*/ 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
/*1*/ 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
/*2*/ 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
/*3*/ 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
/*4*/ 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
/*5*/ 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
/*6*/ 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
/*7*/ 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
/*8*/ 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
/*9*/ 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
/*a*/ 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
/*b*/ 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
/*c*/ 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
/*d*/ 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
/*e*/ 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
/*f*/ 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48
];
/// <summary>
/// 加密 非线性τ函数B=τ(A)
/// </summary>
/// <param name="b"></param>
/// <param name="i"></param>
/// <returns></returns>
private static long GetULongByBe(byte[] b, int i) => ((long)(b[i] & 0xff) << 24) | (uint)((b[i + 1] & 0xff) << 16) | (uint)((b[i + 2] & 0xff) << 8) | (b[i + 3] & 0xff & 0xffffffffL);
/// <summary>
/// 解密 非线性τ函数B=τ(A)
/// </summary>
/// <param name="n"></param>
/// <param name="b"></param>
/// <param name="i"></param>
private static void PutULongToBe(long n, byte[] b, int i)
{
b[i] = (byte)(int)(0xFF & (n >> 24));
b[i + 1] = (byte)(int)(0xFF & (n >> 16));
b[i + 2] = (byte)(int)(0xFF & (n >> 8));
b[i + 3] = (byte)(int)(0xFF & n);
}
private static long SHL(long x, int n) => (x & 0xFFFFFFFF) << n;
/// <summary>
/// 循环移位,为32位的x循环左移n位
/// </summary>
/// <param name="x"></param>
/// <param name="n"></param>
/// <returns></returns>
private static long RotL(long x, int n) => SHL(x, n) | (x >> (32 - n));
/// <summary>
/// 将密钥逆序
/// </summary>
/// <param name="sk"></param>
/// <param name="i"></param>
private static void Swap(long[] sk, int i) => (sk[i], sk[31 - i]) = (sk[31 - i], sk[i]);
/// <summary>
/// Sm4的S盒取值
/// </summary>
/// <param name="inch"></param>
/// <returns></returns>
private byte SBox(byte inch) => SBoxTable[inch & 0xFF];
/// <summary>
/// 线性变换 L
/// </summary>
/// <param name="ka"></param>
/// <returns></returns>
private long Lt(long ka)
{
var a = new byte[4];
var b = new byte[4];
PutULongToBe(ka, a, 0);
b[0] = SBox(a[0]);
b[1] = SBox(a[1]);
b[2] = SBox(a[2]);
b[3] = SBox(a[3]);
var bb = GetULongByBe(b, 0);
return bb ^ RotL(bb, 2) ^ RotL(bb, 10) ^ RotL(bb, 18) ^ RotL(bb, 24);
}
/// <summary>
/// 轮函数 F
/// </summary>
/// <param name="x0"></param>
/// <param name="x1"></param>
/// <param name="x2"></param>
/// <param name="x3"></param>
/// <param name="rk"></param>
/// <returns></returns>
private long F(long x0, long x1, long x2, long x3, long rk) => x0 ^ Lt(x1 ^ x2 ^ x3 ^ rk);
/// <summary>
/// 轮密钥rk
/// </summary>
/// <param name="ka"></param>
/// <returns></returns>
private long CalcRK(long ka)
{
var a = new byte[4];
var b = new byte[4];
PutULongToBe(ka, a, 0);
b[0] = SBox(a[0]);
b[1] = SBox(a[1]);
b[2] = SBox(a[2]);
b[3] = SBox(a[3]);
var bb = GetULongByBe(b, 0);
return bb ^ RotL(bb, 13) ^ RotL(bb, 23);
}
/// <summary>
/// 加密密钥
/// </summary>
/// <param name="SK"></param>
/// <param name="key"></param>
private void SetKey(long[] SK, byte[] key)
{
var MK = new long[4];
var k = new long[36];
var i = 0;
MK[0] = GetULongByBe(key, 0);
MK[1] = GetULongByBe(key, 4);
MK[2] = GetULongByBe(key, 8);
MK[3] = GetULongByBe(key, 12);
k[0] = MK[0] ^ FK[0];
k[1] = MK[1] ^ FK[1];
k[2] = MK[2] ^ FK[2];
k[3] = MK[3] ^ FK[3];
for (; i < 32; i++)
{
k[i + 4] = k[i] ^ CalcRK(k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ CK[i]);
SK[i] = k[i + 4];
}
}
/// <summary>
/// 解密函数
/// </summary>
/// <param name="sk">轮密钥</param>
/// <param name="input">输入分组的密文</param>
/// <param name="output">输出的对应的分组明文</param>
private void OneRound(long[] sk, byte[] input, byte[] output)
{
var i = 0;
var ul_buf = new long[36];
ul_buf[0] = GetULongByBe(input, 0);
ul_buf[1] = GetULongByBe(input, 4);
ul_buf[2] = GetULongByBe(input, 8);
ul_buf[3] = GetULongByBe(input, 12);
while (i < 32)
{
ul_buf[i + 4] = F(ul_buf[i], ul_buf[i + 1], ul_buf[i + 2], ul_buf[i + 3], sk[i]);
i++;
}
PutULongToBe(ul_buf[35], output, 0);
PutULongToBe(ul_buf[34], output, 4);
PutULongToBe(ul_buf[33], output, 8);
PutULongToBe(ul_buf[32], output, 12);
}
/// <summary>
/// 补足 16 进制字符串的 0 字符,返回不带 0x 的16进制字符串
/// </summary>
/// <param name="input"></param>
/// <param name="mode">1表示加密0表示解密</param>
/// <returns></returns>
private static byte[] Padding(byte[] input, Sm4Mode mode)
{
byte[] ret;
if (mode is Sm4Mode.Encrypt)
{
var p = 16 - input.Length % 16;
ret = new byte[input.Length + p];
Array.Copy(input, 0, ret, 0, input.Length);
for (var i = 0; i < p; i++)
{
ret[input.Length + i] = (byte)p;
}
}
else
{
int p = input[^1];
ret = new byte[input.Length - p];
Array.Copy(input, 0, ret, 0, input.Length - p);
}
return ret;
}
/// <summary>
/// 设置加密的key
/// </summary>
/// <param name="ctx"></param>
/// <param name="key"></param>
internal void SetKeyEnc(Sm4Context ctx, byte[] key)
{
ctx.Mode = Sm4Mode.Encrypt;
SetKey(ctx.Key, key);
}
/// <summary>
/// 设置解密的key
/// </summary>
/// <param name="ctx"></param>
/// <param name="key"></param>
internal void SetKeyDec(Sm4Context ctx, byte[] key)
{
ctx.Mode = Sm4Mode.Decrypt;
SetKey(ctx.Key, key);
for (var i = 0; i < 16; i++)
{
Swap(ctx.Key, i);
}
}
internal byte[] ECB(Sm4Context ctx, byte[] input)
{
if (ctx is { IsPadding: true, Mode: Sm4Mode.Encrypt })
{
input = Padding(input, Sm4Mode.Encrypt);
}
var length = input.Length;
var bins = new byte[length];
Array.Copy(input, 0, bins, 0, length);
var bous = new byte[length];
for (var i = 0; length > 0; length -= 16, i++)
{
var inBytes = new byte[16];
var outBytes = new byte[16];
Array.Copy(bins, i * 16, inBytes, 0, length > 16 ? 16 : length);
OneRound(ctx.Key, inBytes, outBytes);
Array.Copy(outBytes, 0, bous, i * 16, length > 16 ? 16 : length);
}
if (ctx is { IsPadding: true, Mode: Sm4Mode.Decrypt })
{
bous = Padding(bous, Sm4Mode.Decrypt);
}
return bous;
}
internal byte[] CBC(Sm4Context ctx, byte[] iv, byte[] input)
{
if (ctx is { IsPadding: true, Mode: Sm4Mode.Encrypt }) input = Padding(input, Sm4Mode.Encrypt);
var length = input.Length;
var bins = new byte[length];
Array.Copy(input, 0, bins, 0, length);
var bousList = new List<byte>();
int i;
if (ctx.Mode is Sm4Mode.Encrypt)
{
for (var j = 0; length > 0; length -= 16, j++)
{
var inBytes = new byte[16];
var outBytes = new byte[16];
var out1 = new byte[16];
Array.Copy(bins, j * 16, inBytes, 0, length > 16 ? 16 : length);
for (i = 0; i < 16; i++)
{
outBytes[i] = (byte)(inBytes[i] ^ iv[i]);
}
OneRound(ctx.Key, outBytes, out1);
Array.Copy(out1, 0, iv, 0, 16);
for (var k = 0; k < 16; k++)
{
bousList.Add(out1[k]);
}
}
}
else
{
var temp = new byte[16];
for (var j = 0; length > 0; length -= 16, j++)
{
var inBytes = new byte[16];
var outBytes = new byte[16];
var out1 = new byte[16];
Array.Copy(bins, j * 16, inBytes, 0, length > 16 ? 16 : length);
Array.Copy(inBytes, 0, temp, 0, 16);
OneRound(ctx.Key, inBytes, outBytes);
for (i = 0; i < 16; i++)
{
out1[i] = (byte)(outBytes[i] ^ iv[i]);
}
Array.Copy(temp, 0, iv, 0, 16);
for (var k = 0; k < 16; k++)
{
bousList.Add(out1[k]);
}
}
}
return ctx is { IsPadding: true, Mode: Sm4Mode.Decrypt } ? Padding(bousList.ToArray(), Sm4Mode.Decrypt) : bousList.ToArray();
}
}

@ -0,0 +1,19 @@
namespace NPin.Framework.Core.Crypt.SM4;
internal sealed class Sm4Context
{
/// <summary>
/// 是否补足16进制字符串
/// </summary>
internal bool IsPadding { get; set; } = true;
/// <summary>
/// 加密或者解密
/// </summary>
internal Sm4Mode Mode { get; set; } = Sm4Mode.Encrypt;
/// <summary>
/// 密钥
/// </summary>
internal long[] Key { get; } = new long[32];
}

@ -0,0 +1,116 @@
using System.Text;
using Org.BouncyCastle.Utilities.Encoders;
namespace NPin.Framework.Core.Crypt.SM4;
/// <summary>
/// SM4 加解密
/// </summary>
public static class Sm4Crypt
{
/// <summary>
/// 加密ECB模式
/// </summary>
/// <param name="secretKey">密钥</param>
/// <param name="hexString">密钥是否是十六进制</param>
/// <param name="plainText">二进制格式加密的内容</param>
/// <returns>返回二进制格式密文</returns>
public static byte[] EncryptECB(string secretKey, bool hexString, byte[] plainText)
{
var ctx = new Sm4Context
{
IsPadding = true,
Mode = Sm4Mode.Encrypt
};
var keyBytes = hexString ? Hex.Decode(secretKey) : Encoding.UTF8.GetBytes(secretKey);
var sm4 = new Sm4();
sm4.SetKeyEnc(ctx, keyBytes);
return sm4.ECB(ctx, plainText);
}
/// <summary>
/// 解密ECB模式
/// </summary>
/// <param name="secretKey">密钥</param>
/// <param name="hexString">密钥是否是十六进制</param>
/// <param name="cipherBytes">二进制格式密文</param>
/// <returns>二进制格式明文</returns>
public static byte[] DecryptECB(string secretKey, bool hexString, byte[] cipherBytes)
{
var ctx = new Sm4Context
{
IsPadding = true,
Mode = Sm4Mode.Decrypt
};
var keyBytes = hexString ? Hex.Decode(secretKey) : Encoding.UTF8.GetBytes(secretKey);
var sm4 = new Sm4();
sm4.SetKeyDec(ctx, keyBytes);
return sm4.ECB(ctx, cipherBytes);
}
/// <summary>
/// 加密CBC模式
/// </summary>
/// <param name="secretKey">密钥</param>
/// <param name="hexString">密钥和IV是否是十六进制</param>
/// <param name="iv"></param>
/// <param name="plainText">二进制格式明文</param>
/// <returns>返回二进制密文数组</returns>
public static byte[] EncryptCBC(string secretKey, bool hexString, string iv, byte[] plainText)
{
var ctx = new Sm4Context
{
IsPadding = true,
Mode = Sm4Mode.Encrypt
};
byte[] keyBytes;
byte[] ivBytes;
if (hexString)
{
keyBytes = Hex.Decode(secretKey);
ivBytes = Hex.Decode(iv);
}
else
{
keyBytes = Encoding.UTF8.GetBytes(secretKey);
ivBytes = Encoding.UTF8.GetBytes(iv);
}
var sm4 = new Sm4();
sm4.SetKeyEnc(ctx, keyBytes);
return sm4.CBC(ctx, ivBytes, plainText);
}
/// <summary>
/// 解密CBC模式
/// </summary>
/// <param name="secretKey">16进制密钥</param>
/// <param name="hexString">密钥和IV是否是十六进制</param>
/// <param name="iv"></param>
/// <param name="cipherText">二进制格式密文</param>
/// <returns>返回二进制格式明文</returns>
public static byte[] DecryptCBC(string secretKey, bool hexString, string iv, byte[] cipherText)
{
var ctx = new Sm4Context
{
IsPadding = true,
Mode = Sm4Mode.Decrypt
};
byte[] keyBytes;
byte[] ivBytes;
if (hexString)
{
keyBytes = Hex.Decode(secretKey);
ivBytes = Hex.Decode(iv);
}
else
{
keyBytes = Encoding.UTF8.GetBytes(secretKey);
ivBytes = Encoding.UTF8.GetBytes(iv);
}
var sm4 = new Sm4();
sm4.SetKeyDec(ctx, keyBytes);
return sm4.CBC(ctx, ivBytes, cipherText);
}
}

@ -0,0 +1,7 @@
namespace NPin.Framework.Core.Crypt.SM4;
public enum Sm4Mode
{
Encrypt,
Decrypt
}

@ -2,6 +2,7 @@
<Import Project="..\..\common.props"/> <Import Project="..\..\common.props"/>
<ItemGroup> <ItemGroup>
<PackageReference Include="BouncyCastle.Cryptography" Version="2.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0"/> <PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0"/>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3"/> <PackageReference Include="Newtonsoft.Json" Version="13.0.3"/>
<PackageReference Include="Volo.Abp.Core" Version="8.0.0"/> <PackageReference Include="Volo.Abp.Core" Version="8.0.0"/>

@ -0,0 +1,6 @@
namespace NPin.Framework.SqlSugarCore.Abstractions.Data;
public interface IEnabled
{
bool IsEnabled { get; set; }
}

@ -0,0 +1,9 @@
namespace NPin.Framework.SqlSugarCore.Abstractions.Data;
public interface IOrderNum
{
/// <summary>
/// 排序号
/// </summary>
int OrderNum { get; set; }
}

@ -13,6 +13,7 @@ public interface ISqlSugarDbConnectionCreator
Action<string, SugarParameter[]> OnLogExecuting { get; set; } Action<string, SugarParameter[]> OnLogExecuting { get; set; }
Action<string, SugarParameter[]> OnLogExecuted { get; set; } Action<string, SugarParameter[]> OnLogExecuted { get; set; }
Action<PropertyInfo, EntityColumnInfo> EntityService { get; set; } Action<PropertyInfo, EntityColumnInfo> EntityService { get; set; }
Action<Type, EntityInfo> EntityNameService { get; set; }
ConnectionConfig Build(Action<ConnectionConfig>? action = null); ConnectionConfig Build(Action<ConnectionConfig>? action = null);
void SetDbAop(ISqlSugarClient currentDb); void SetDbAop(ISqlSugarClient currentDb);

@ -21,6 +21,8 @@ public class SqlSugarDbConnectionCreator : ISqlSugarDbConnectionCreator, ITransi
[DisablePropertyInjection] public Action<PropertyInfo, EntityColumnInfo> EntityService { get; set; } [DisablePropertyInjection] public Action<PropertyInfo, EntityColumnInfo> EntityService { get; set; }
[DisablePropertyInjection] public Action<Type, EntityInfo> EntityNameService { get; set; }
public DbConnOptions Options { get; } public DbConnOptions Options { get; }
public SqlSugarDbConnectionCreator(IOptions<DbConnOptions> options) public SqlSugarDbConnectionCreator(IOptions<DbConnOptions> options)
@ -87,6 +89,10 @@ public class SqlSugarDbConnectionCreator : ISqlSugarDbConnectionCreator, ITransi
} }
EntityService(c, p); EntityService(c, p);
},
EntityNameService = (t, e) =>
{
EntityNameService(t, e);
} }
}, },
// Aop // Aop

@ -5,7 +5,6 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using NPin.Framework.SqlSugarCore.Abstractions; using NPin.Framework.SqlSugarCore.Abstractions;
using SqlSugar; using SqlSugar;
using Volo.Abp;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
@ -47,6 +46,7 @@ public class SqlSugarDbContext : ISqlSugarDbContext
var connectionCreator = LazyServiceProvider.LazyGetRequiredService<ISqlSugarDbConnectionCreator>(); var connectionCreator = LazyServiceProvider.LazyGetRequiredService<ISqlSugarDbConnectionCreator>();
connectionCreator.OnSqlSugarClientConfig = OnSqlSugarClientConfig; connectionCreator.OnSqlSugarClientConfig = OnSqlSugarClientConfig;
connectionCreator.EntityService = EntityService; connectionCreator.EntityService = EntityService;
connectionCreator.EntityNameService = EntityNameService;
connectionCreator.DataExecuting = DataExecuting; connectionCreator.DataExecuting = DataExecuting;
connectionCreator.DataExecuted = DataExecuted; connectionCreator.DataExecuted = DataExecuted;
connectionCreator.OnLogExecuting = OnLogExecuting; connectionCreator.OnLogExecuting = OnLogExecuting;
@ -204,6 +204,9 @@ public class SqlSugarDbContext : ISqlSugarDbContext
/// <summary> /// <summary>
/// 实体配置 /// 实体配置
/// 自动主键
/// 自动Ignore关联配置导航
/// 开启下划线
/// </summary> /// </summary>
/// <param name="property"></param> /// <param name="property"></param>
/// <param name="column"></param> /// <param name="column"></param>
@ -213,10 +216,25 @@ public class SqlSugarDbContext : ISqlSugarDbContext
{ {
column.IsIgnore = true; column.IsIgnore = true;
} }
if (property.Name == nameof(Entity<object>.Id)) if (property.Name == nameof(Entity<object>.Id))
{ {
column.IsPrimarykey = true; column.IsPrimarykey = true;
} }
column.DbColumnName = UtilMethods.ToUnderLine(column.DbColumnName);
}
/// <summary>
/// EntityName 配置
/// 开启下划线
/// </summary>
/// <param name="type"></param>
/// <param name="entity"></param>
protected virtual void EntityNameService(Type type, EntityInfo entity)
{
// 开启下划线
entity.DbTableName = UtilMethods.ToUnderLine(entity.DbTableName);
} }
public void Backup() public void Backup()

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<ItemGroup>
<ProjectReference Include="..\..\..\framework\NPin.Framework.Ddd.Application.Contracts\NPin.Framework.Ddd.Application.Contracts.csproj" />
<ProjectReference Include="..\NPin.Framework.Upms.Domain.Shared\NPin.Framework.Upms.Domain.Shared.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,12 @@
using NPin.Framework.Ddd.Application.Contracts;
using NPin.Framework.Upms.Domain.Shared;
namespace NPin.Framework.Upms.Application.Contracts;
[DependsOn(
typeof(NPinFrameworkUpmsDomainSharedModule),
typeof(NPinFrameworkDddApplicationContractsModule)
)]
public class NPinFrameworkUpmsApplicationContractsModule : AbpModule
{
}

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<ItemGroup>
<ProjectReference Include="..\..\..\framework\NPin.Framework.Ddd.Application\NPin.Framework.Ddd.Application.csproj" />
<ProjectReference Include="..\NPin.Framework.Upms.Application.Contracts\NPin.Framework.Upms.Application.Contracts.csproj" />
<ProjectReference Include="..\NPin.Framework.Upms.Domain\NPin.Framework.Upms.Domain.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Lazy.Captcha.Core" Version="2.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.7" />
<PackageReference Include="Volo.Abp.BackgroundWorkers.Quartz" Version="8.0.0" />
</ItemGroup>
</Project>

@ -0,0 +1,22 @@
using Microsoft.Extensions.DependencyInjection;
using NPin.Framework.Ddd.Application;
using NPin.Framework.Upms.Application.Contracts;
using NPin.Framework.Upms.Domain;
using Volo.Abp.BackgroundWorkers.Quartz;
namespace NPin.Framework.Upms.Application;
[DependsOn(
typeof(NPinFrameworkUpmsApplicationContractsModule),
typeof(NPinFrameworkUpmsDomainModule),
// framework
typeof(NPinFrameworkDddApplicationModule),
typeof(AbpBackgroundWorkersQuartzModule)
)]
public class NPinFrameworkUpmsApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddCaptcha();
}
}

@ -0,0 +1,26 @@
namespace NPin.Framework.Upms.Domain.Shared.Caches;
public class CaptchaPhoneCacheItem
{
public string Code { get; set; }
public CaptchaPhoneCacheItem(string code)
{
Code = code;
}
}
public class CaptchaPhoneCacheKey
{
public string Phone { get; set; }
public CaptchaPhoneCacheKey(string phone)
{
Phone = phone;
}
public override string ToString()
{
return $"Phone: {Phone}";
}
}

@ -0,0 +1,16 @@
namespace NPin.Framework.Upms.Domain.Shared.Consts;
public class UserConst
{
// 子租户管理员
public const string Admin = "admin";
public const string AdminRoleCode = "Admin";
public const string AdminPermissionCode = "*:*:*";
// 租户管理员
public const string TenantAdmin = "tadmin";
public const string TenantAdminPermissionCode = "*";
// 角色
public const string DefaultRoleCode = "Default";
}

@ -0,0 +1,32 @@
namespace NPin.Framework.Upms.Domain.Shared.Enums;
/// <summary>
/// 数据范围枚举
/// </summary>
public enum DataScopeEnum
{
/// <summary>
/// 所有数据
/// </summary>
All = 0,
/// <summary>
/// 自定义
/// </summary>
Custom = 1,
/// <summary>
/// 本部门
/// </summary>
Dept = 2,
/// <summary>
/// 部门以及子部门
/// </summary>
DeptFollow = 3,
/// <summary>
/// 只有自己
/// </summary>
User = 4
}

@ -0,0 +1,19 @@
namespace NPin.Framework.Upms.Domain.Shared.Enums;
public enum GenderEnum
{
/// <summary>
/// 保密
/// </summary>
Secrecy = 0,
/// <summary>
/// 男性
/// </summary>
Male = 1,
/// <summary>
/// 女性
/// </summary>
Female = 2
}

@ -0,0 +1,14 @@
namespace NPin.Framework.Upms.Domain.Shared.Enums;
public enum JobTypeEnum
{
/// <summary>
/// Cron表达式
/// </summary>
Cron,
/// <summary>
/// 基于毫秒
/// </summary>
Milliseconds
}

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<ItemGroup>
<ProjectReference Include="..\..\..\framework\NPin.Framework.Mapster\NPin.Framework.Mapster.csproj" />
<ProjectReference Include="..\..\..\framework\NPin.Framework.SqlSugarCore.Abstractions\NPin.Framework.SqlSugarCore.Abstractions.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Users.Domain.Shared" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Dtos\" />
<Folder Include="Etos\" />
<Folder Include="Model\" />
</ItemGroup>
</Project>

@ -0,0 +1,22 @@
using Microsoft.Extensions.DependencyInjection;
using NPin.Framework.Mapster;
using NPin.Framework.Upms.Domain.Shared.Options;
using Volo.Abp.Domain;
namespace NPin.Framework.Upms.Domain.Shared;
[DependsOn(
typeof(AbpDddDomainSharedModule),
typeof(NPinFrameworkMapsterModule)
)]
public class NPinFrameworkUpmsDomainSharedModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
// 配置文件读取
Configure<JwtOptions>(configuration.GetSection(nameof(JwtOptions)));
Configure<RefreshJwtOptions>(configuration.GetSection(nameof(RefreshJwtOptions)));
Configure<UpmsOptions>(configuration.GetSection(nameof(UpmsOptions)));
}
}

@ -0,0 +1,31 @@
namespace NPin.Framework.Upms.Domain.Shared.OperLog;
[AttributeUsage(AttributeTargets.Method)]
public class OperLogAttribute: Attribute
{
/// <summary>
/// 操作类型
/// </summary>
public OperTypeEnum OperType { get; set; }
/// <summary>
/// 日志标题
/// </summary>
public string Title { get; set; }
/// <summary>
/// 是否保存请求数据
/// </summary>
public bool IsSaveRequestData { get; set; } = true;
/// <summary>
/// 是否保存返回数据
/// </summary>
public bool IsSaveResponseData { get; set; } = true;
public OperLogAttribute(string title, OperTypeEnum operationType)
{
Title = title;
OperType = operationType;
}
}

@ -0,0 +1,19 @@
namespace NPin.Framework.Upms.Domain.Shared.OperLog;
/// <summary>
/// 操作类型枚举
/// </summary>
public enum OperTypeEnum
{
Insert = 1,
Update = 2,
Delete = 3,
//
Auth = 4,
Export = 5,
Import = 6,
ForcedOut = 7,
GenerateCode = 8,
ClearData = 9
}

@ -0,0 +1,17 @@
namespace NPin.Framework.Upms.Domain.Shared.Options;
/// <summary>
/// 阿里云SDK相关配置
/// </summary>
public class AliyunOptions
{
public string AccessKeyId { get; set; }
public string AccessKeySecret { get; set; }
public AliyunSms Sms { get; set; }
}
public class AliyunSms
{
public string SignName { get; set; }
public string TemplateCode { get; set; }
}

@ -0,0 +1,15 @@
namespace NPin.Framework.Upms.Domain.Shared.Options;
/// <summary>
/// JWT 配置
/// </summary>
public class JwtOptions
{
public string Issuer { get; set; } = "NoahLan";
public string Audience { get; set; } = "NoahLan";
public string SecurityKey { get; set; } = "892u4j1803qj23jro0fjkf8bmsdf9nb9mf92834u23jdf923jrnmvasbceqwt347562tgdhdnsv9wevbnop";
public long ExpiresMinuteTime { get; set; } = 120;
}

@ -0,0 +1,8 @@
namespace NPin.Framework.Upms.Domain.Shared.Options;
/// <summary>
/// 刷新Token 配置
/// </summary>
public class RefreshJwtOptions : JwtOptions
{
}

@ -0,0 +1,32 @@
namespace NPin.Framework.Upms.Domain.Shared.Options;
/// <summary>
/// Upms模块的总体配置
/// </summary>
public class UpmsOptions
{
/// <summary>
/// 超级管理员默认密码
/// </summary>
public string AdminPassword { get; set; } = "a123456";
/// <summary>
/// 租户超级管理员默认密码
/// </summary>
public string TenantAdminPassword { get; set; } = "a123456";
/// <summary>
/// 是否开启登录图形验证码
/// </summary>
public bool EnableCaptcha { get; set; } = false;
/// <summary>
/// 是否开启注册功能
/// </summary>
public bool EnableRegister { get; set; } = false;
/// <summary>
/// 是否开启数据库自动o备份功能
/// </summary>
public bool EnableDataBaseBackup { get; set; } = false;
}

@ -0,0 +1,8 @@
namespace NPin.Framework.Upms.Domain.Authorization;
/// <summary>
/// 数据权限过滤接口可通过DataFilter配置关闭
/// </summary>
public interface IDataPermission
{
}

@ -0,0 +1,88 @@
using Microsoft.Win32.SafeHandles;
using NPin.Framework.SqlSugarCore.Abstractions.Data;
using NPin.Framework.Upms.Domain.Shared.Enums;
using SqlSugar;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("User")]
public class UserEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IEnabled, IOrderNum
{
#region User
[SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; }
[SugarColumn(ColumnDescription = "用户名")]
public string Username { get; set; } = string.Empty;
[SugarColumn(ColumnDescription = "手机号码")]
public string PhoneNumber { get; set; }
[SugarColumn(ColumnDescription = "邮箱")]
public string? Email { get; set; }
[SugarColumn(ColumnDescription = "昵称")]
public string? Nickname { get; set; }
[SugarColumn(ColumnDescription = "密码")]
public string Password { get; set; } = string.Empty;
[SugarColumn(ColumnDescription = "简介")]
public string? Introduction { get; set; }
[SugarColumn(ColumnDescription = "性别")]
public GenderEnum Gender { get; set; } = GenderEnum.Secrecy;
[SugarColumn(ColumnDescription = "注册IP地址")]
public string? IpAddr { get; set; }
[SugarColumn(ColumnDescription = "头像")]
public string? Avatar { get; set; }
#endregion
#region Implements
/// <summary>
/// 逻辑删除
/// </summary>
public bool IsDeleted { get; }
public DateTime CreationTime { get; }
public Guid? CreatorId { get; }
public DateTime? LastModificationTime { get; }
public Guid? LastModifierId { get; }
/// <summary>
/// 是否启用
/// </summary>
public bool IsEnabled { get; set; }
public int OrderNum { get; set; }
#endregion
#region 关联关系(导航)
#endregion
public UserEntity()
{
}
public UserEntity(string username, string phoneNumber, string password, string? nickname)
{
Username = username;
PhoneNumber = phoneNumber;
if (username.IsNullOrEmpty())
{
username = $"用户{phoneNumber}";
}
Nickname = nickname.IsNullOrWhiteSpace() ? username : nickname;
// Password
// SafeNCryptHandle
}
}

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<ItemGroup>
<ProjectReference Include="..\..\..\framework\NPin.Framework.Caching.FreeRedis\NPin.Framework.Caching.FreeRedis.csproj" />
<ProjectReference Include="..\..\..\framework\NPin.Framework.SqlSugarCore.Abstractions\NPin.Framework.SqlSugarCore.Abstractions.csproj" />
<ProjectReference Include="..\NPin.Framework.Upms.Domain.Shared\NPin.Framework.Upms.Domain.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="2.0.24" />
<PackageReference Include="IPTools.International" Version="1.6.0" />
<PackageReference Include="TencentCloudSDK" Version="3.0.952" />
<PackageReference Include="UAParser" Version="3.1.47" />
<PackageReference Include="Volo.Abp.AspNetCore.SignalR" Version="8.0.0" />
<PackageReference Include="Volo.Abp.Caching" Version="8.0.0" />
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="8.0.0" />
</ItemGroup>
</Project>

@ -0,0 +1,32 @@
using Microsoft.Extensions.DependencyInjection;
using NPin.Framework.Caching.FreeRedis;
using NPin.Framework.Upms.Domain.Shared;
using Volo.Abp.AspNetCore.SignalR;
using Volo.Abp.Caching;
using Volo.Abp.Domain;
namespace NPin.Framework.Upms.Domain;
[DependsOn(
typeof(NPinFrameworkUpmsDomainSharedModule),
typeof(NPinFrameworkCachingFreeRedisModule),
// Abp
typeof(AbpAspNetCoreSignalRModule),
typeof(AbpDddDomainModule),
typeof(AbpCachingModule)
)]
public class NPinFrameworkUpmsDomainModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var services = context.Services;
var configuration = services.GetConfiguration();
services.AddControllers(opts =>
{
// opts.Filters.Add()
});
// 配置短信
// Configure<AliyunOptions>();
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<ItemGroup>
<ProjectReference Include="..\..\..\framework\NPin.Framework.Mapster\NPin.Framework.Mapster.csproj" />
<ProjectReference Include="..\..\..\framework\NPin.Framework.SqlSugarCore\NPin.Framework.SqlSugarCore.csproj" />
<ProjectReference Include="..\NPin.Framework.Upms.Domain\NPin.Framework.Upms.Domain.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,19 @@
using NPin.Framework.Mapster;
using NPin.Framework.SqlSugarCore;
using NPin.Framework.Upms.Domain;
namespace NPin.Framework.Upms.SqlSugarCore;
[DependsOn(
typeof(NPinFrameworkUpmsDomainModule),
// framework
typeof(NPinFrameworkMapsterModule),
typeof(NPinFrameworkSqlSugarCoreModule)
)]
public class NPinFrameworkUpmsSqlSugarCoreModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
}
}

@ -0,0 +1,49 @@
using NPin.Framework.SqlSugarCore;
using NPin.Framework.Upms.Domain.Authorization;
using NPin.Framework.Upms.Domain.Shared.Consts;
using SqlSugar;
using Volo.Abp.DependencyInjection;
namespace NPin.Framework.Upms.SqlSugarCore;
public class NPinUpmsDbContext : SqlSugarDbContext
{
public NPinUpmsDbContext(IAbpLazyServiceProvider lazyServiceProvider) : base(lazyServiceProvider)
{
}
protected override void CustomDataFilter(ISqlSugarClient sqlSugarClient)
{
if (DataFilter.IsEnabled<IDataPermission>())
{
DataPermissionFilter(sqlSugarClient);
}
base.CustomDataFilter(sqlSugarClient);
}
/// <summary>
/// 数据权限过滤
/// </summary>
/// <param name="sqlSugarClient"></param>
protected void DataPermissionFilter(ISqlSugarClient sqlSugarClient)
{
// 当前无登录用户,无需过滤
if (CurrentUser.Id == null) return;
// 管理员角色 不进行过滤
if (CurrentUser.UserName.Equals(UserConst.Admin) ||
CurrentUser.Roles.Any(r => r.Equals(UserConst.AdminRoleCode)))
{
return;
}
// var expUser = Expressionable.Create<>();
// var expRole = Expressionable.Create<>();
// 无岗位 or 无角色 只能看自己
// sqlSugarClient.QueryFilter.AddTableFilter()
}
}
Loading…
Cancel
Save