diff --git a/Lazy.Captcha.Core/CaptchaOptions.cs b/Lazy.Captcha.Core/CaptchaOptions.cs index 453987fad8609bbbd3d3c686742ee83ef2346368..12ad5ed3b819bcbd2c149eeebbddfa61e5c3e971 100644 --- a/Lazy.Captcha.Core/CaptchaOptions.cs +++ b/Lazy.Captcha.Core/CaptchaOptions.cs @@ -1,4 +1,5 @@ -using Lazy.Captcha.Core.Generator; +using System; +using Lazy.Captcha.Core.Generator; using Lazy.Captcha.Core.Generator.Image.Option; namespace Lazy.Captcha.Core @@ -27,7 +28,7 @@ namespace Lazy.Captcha.Core if (value.ContainsChinese()) { - this.ImageOption.FontFamily = DefaultFontFamilys.Instance.Kaiti; + this.ImageOption.FontFamily = DefaultFontFamilies.Instance.Kaiti; } _captchaType = value; @@ -52,8 +53,18 @@ namespace Lazy.Captcha.Core /// /// 存储键前缀 /// - public virtual string StoreageKeyPrefix { get; set; } + public virtual string StorageKeyPrefix { get; set; } + /// + /// 存储键前缀 + /// + [Obsolete("由于拼写错误,应被废弃。请使用 `StorageKeyPrefix`。", false)] + public virtual string StoreageKeyPrefix + { + get => StorageKeyPrefix; + set => StorageKeyPrefix = value; + } + /// /// 图片选项 /// diff --git a/Lazy.Captcha.Core/CaptchaServiceBuilder.cs b/Lazy.Captcha.Core/CaptchaServiceBuilder.cs index 82b610a2dc17484e4a76582ae9a8161987d96190..8d807b470534f37fd97da41850de8fd49b7549a7 100644 --- a/Lazy.Captcha.Core/CaptchaServiceBuilder.cs +++ b/Lazy.Captcha.Core/CaptchaServiceBuilder.cs @@ -12,13 +12,13 @@ namespace Lazy.Captcha.Core /// public class CaptchaServiceBuilder { - private CaptchaOptions CaptchaOptions; - private IStorage InnerStorage; + private CaptchaOptions CaptchaOptions; + private IStorage InnerStorage; - public CaptchaServiceBuilder() + public CaptchaServiceBuilder() { CaptchaOptions = GenerateDefaultOptions(); - InnerStorage = new MemeoryStorage(); + InnerStorage = new MemoryStorage(); } public static CaptchaServiceBuilder New() @@ -97,11 +97,23 @@ namespace Lazy.Captcha.Core /// /// 存储键前缀 /// - /// + /// /// - public CaptchaServiceBuilder StoreageKeyPrefix(string storeageKeyPrefix) + public CaptchaServiceBuilder StorageKeyPrefix(string storageKeyPrefix) { - CaptchaOptions.StoreageKeyPrefix = storeageKeyPrefix; + CaptchaOptions.StorageKeyPrefix = storageKeyPrefix; + return this; + } + + /// + /// 存储键前缀 + /// + /// + /// + [Obsolete("由于拼写错误,该方法应被废弃。使用 `StorageKeyPrefix`。", false)] + public CaptchaServiceBuilder StoreageKeyPrefix(string storageKeyPrefix) + { + CaptchaOptions.StorageKeyPrefix = storageKeyPrefix; return this; } diff --git a/Lazy.Captcha.Core/CaptchaServiceCollectionExtensions.cs b/Lazy.Captcha.Core/CaptchaServiceCollectionExtensions.cs index dd6c34266553f320caaa4c741c5afed55e425243..51437aee3b8834dc434b52d3436b1a20dc263b9d 100644 --- a/Lazy.Captcha.Core/CaptchaServiceCollectionExtensions.cs +++ b/Lazy.Captcha.Core/CaptchaServiceCollectionExtensions.cs @@ -6,7 +6,6 @@ using System.Linq; using Lazy.Captcha.Core; using Lazy.Captcha.Core.RateLimit; using Lazy.Captcha.Core.Storage; -using Lazy.Captcha.Core.Storeage; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection.Extensions; using SkiaSharp; @@ -35,7 +34,7 @@ namespace Microsoft.Extensions.DependencyInjection var fontFamily = configuration?.GetSection("CaptchaOptions:ImageOption:FontFamily")?.Value; if (!string.IsNullOrWhiteSpace(fontFamily)) { - options.ImageOption.FontFamily = DefaultFontFamilys.Instance.GetFontFamily(fontFamily); + options.ImageOption.FontFamily = DefaultFontFamilies.Instance.GetFontFamily(fontFamily); } var backgroundColor = configuration?.GetSection("CaptchaOptions:ImageOption:BackgroundColor")?.Value; diff --git a/Lazy.Captcha.Core/DefaultCaptcha.cs b/Lazy.Captcha.Core/DefaultCaptcha.cs index 4c9e28b8458f9804bc3c665b8472f61757e43326..75cd77b2f65423176df28c60ec48e79f63169306 100644 --- a/Lazy.Captcha.Core/DefaultCaptcha.cs +++ b/Lazy.Captcha.Core/DefaultCaptcha.cs @@ -31,35 +31,37 @@ namespace Lazy.Captcha.Core _captchaImageGenerator = new DefaultCaptchaImageGenerator(); } - // ѡ����� + /// + /// 更新验证码选项 + /// + /// 验证码生成选项 protected virtual void ChangeOptions(CaptchaOptions options) { - } /// - /// ������֤�� + /// 生成验证码 /// - /// ��֤��id - /// ����ʱ�䣬δ�趨��ʹ������ʱ�� + /// 验证码id + /// 缓存时间,未设定则使用配置时间 /// public virtual CaptchaData Generate(string captchaId, int? expirySeconds = null) { var (renderText, code) = _captchaCodeGenerator.Generate(_options.CodeLength); var image = _captchaImageGenerator.Generate(renderText, _options.ImageOption); - expirySeconds = expirySeconds.HasValue ? expirySeconds.Value : _options.ExpirySeconds; + expirySeconds ??= _options.ExpirySeconds; _storage.Set(captchaId, code, DateTime.Now.AddSeconds(expirySeconds.Value).ToUniversalTime()); return new CaptchaData(captchaId, code, image); } /// - /// У�� + /// 校验 /// - /// ��֤��id - /// �û��������֤�� - /// У��ɹ�ʱ�Ƿ��Ƴ�����(���ڶ����֤) - /// У��ʧ��ʱ�Ƿ��Ƴ����� + /// 验证码id + /// 用户输入的验证码 + /// 校验成功时是否移除缓存(用于多次验证) + /// 校验失败时是否移除 /// public virtual bool Validate(string captchaId, string code, bool removeIfSuccess = true, bool removeIfFail = true) { diff --git a/Lazy.Captcha.Core/DefaultFontFamilys.cs b/Lazy.Captcha.Core/DefaultFontFamilies.cs similarity index 45% rename from Lazy.Captcha.Core/DefaultFontFamilys.cs rename to Lazy.Captcha.Core/DefaultFontFamilies.cs index 6e34e706911f29da2b9d09b2464acf22278be3ef..e6bb12d71eb78082aac4f42ece36c7627c28c271 100644 --- a/Lazy.Captcha.Core/DefaultFontFamilys.cs +++ b/Lazy.Captcha.Core/DefaultFontFamilies.cs @@ -6,11 +6,12 @@ using SkiaSharp; namespace Lazy.Captcha.Core { - public class DefaultFontFamilys + public class DefaultFontFamilies { - public static DefaultFontFamilys Instance = new DefaultFontFamilys(); - private static List _fontFamilies = null; - private static Dictionary FamilyNameMapper = new Dictionary + public static readonly DefaultFontFamilies Instance = new DefaultFontFamilies(); + private static readonly List _fontFamilies = []; + + private static readonly Dictionary FamilyNameMapper = new Dictionary { { "actionj", "Action Jackson" }, { "epilog", "Epilog" }, @@ -25,25 +26,22 @@ namespace Lazy.Captcha.Core { "kaiti", "FZKai-Z03" } }; - static DefaultFontFamilys() + static DefaultFontFamilies() { - if (_fontFamilies == null) + if (_fontFamilies.Count != 0) + return; + + var assembly = Assembly.GetExecutingAssembly(); + var names = assembly.GetManifestResourceNames(); + + if (names.Length == 0) { - var assembly = Assembly.GetExecutingAssembly(); - var names = assembly.GetManifestResourceNames(); - _fontFamilies = new List(); - - if (names?.Length > 0 == true) - { - foreach (var name in names) - { - _fontFamilies.Add(SKTypeface.FromStream(assembly.GetManifestResourceStream(name))); - } - } - else - { - throw new Exception($"绘制验证码字体文件加载失败"); - } + throw new Exception("绘制验证码字体文件加载失败"); + } + + foreach (var name in names) + { + _fontFamilies.Add(SKTypeface.FromStream(assembly.GetManifestResourceStream(name))); } } @@ -59,6 +57,7 @@ namespace Lazy.Captcha.Core // 默认字体 realName = FamilyNameMapper[normalizeName]; } + // 改用StartsWith, 某些环境下: Prefix取到的值为Prefix Endangered, Ransom取到的值为Ransom CutUpLetters return _fontFamilies.First(f => f.FamilyName.StartsWith(realName)); } @@ -66,122 +65,62 @@ namespace Lazy.Captcha.Core /// /// ACTIONJ /// - public SKTypeface Actionj - { - get - { - return GetFontFamily("Actionj"); - } - } + public SKTypeface Actionj => GetFontFamily("Actionj"); /// /// Epilog /// - public SKTypeface Epilog - { - get - { - return GetFontFamily("Epilog"); - } - } + public SKTypeface Epilog => GetFontFamily("Epilog"); /// /// Fresnel /// - public SKTypeface Fresnel - { - get - { - return GetFontFamily("Fresnel"); - } - } + public SKTypeface Fresnel => GetFontFamily("Fresnel"); /// /// headache /// - public SKTypeface Headache - { - get - { - return GetFontFamily("Headache"); - } - } + public SKTypeface Headache => GetFontFamily("Headache"); /// /// Lexo /// - public SKTypeface Lexo - { - get - { - return GetFontFamily("Lexo"); - } - } + public SKTypeface Lexo => GetFontFamily("Lexo"); /// /// Prefix /// - public SKTypeface Prefix - { - get - { - return GetFontFamily("Prefix"); - } - } + public SKTypeface Prefix => GetFontFamily("Prefix"); /// /// Progbot /// - public SKTypeface Progbot - { - get - { - return GetFontFamily("Progbot"); - } - } + public SKTypeface Progbot => GetFontFamily("Progbot"); /// /// Ransom /// - public SKTypeface Ransom - { - get - { - return GetFontFamily("Ransom"); - } - } + public SKTypeface Ransom => GetFontFamily("Ransom"); /// /// Robot /// - public SKTypeface Robot - { - get - { - return GetFontFamily("Robot"); - } - } + public SKTypeface Robot => GetFontFamily("Robot"); /// /// Scandal /// - public SKTypeface Scandal - { - get - { - return GetFontFamily("Scandal"); - } - } + public SKTypeface Scandal => GetFontFamily("Scandal"); /// /// 楷体 /// - public SKTypeface Kaiti - { - get - { - return GetFontFamily("Kaiti"); - } - } + public SKTypeface Kaiti => GetFontFamily("Kaiti"); + } + + [Obsolete("拼写错误。请使用 `DefaultFontFamilies` 代替。")] + public class DefaultFontFamilys + { + public static readonly DefaultFontFamilies Instance = DefaultFontFamilies.Instance; } } \ No newline at end of file diff --git a/Lazy.Captcha.Core/Generator/Image/Option/CaptchaImageGeneratorOption.cs b/Lazy.Captcha.Core/Generator/Image/Option/CaptchaImageGeneratorOption.cs index 2b5c4ead2e63931c6b6166419ea04e19f0da75e3..99bfd724c3361e3b6107355a41911d666c82f92c 100644 --- a/Lazy.Captcha.Core/Generator/Image/Option/CaptchaImageGeneratorOption.cs +++ b/Lazy.Captcha.Core/Generator/Image/Option/CaptchaImageGeneratorOption.cs @@ -24,7 +24,7 @@ namespace Lazy.Captcha.Core.Generator.Image.Option /// /// FontFamily /// - public SKTypeface FontFamily { get; set;}= DefaultFontFamilys.Instance.Kaiti; + public SKTypeface FontFamily { get; set;}= DefaultFontFamilies.Instance.Kaiti; /// /// 字体大小 /// diff --git a/Lazy.Captcha.Core/Storage/DefaultStorage.cs b/Lazy.Captcha.Core/Storage/DefaultStorage.cs index f93d0f7bddee62bbe2b69410c2dd0a637e5362eb..0a974f2913e1ee2d5e379ec6d121856dd84a85f2 100644 --- a/Lazy.Captcha.Core/Storage/DefaultStorage.cs +++ b/Lazy.Captcha.Core/Storage/DefaultStorage.cs @@ -3,37 +3,28 @@ using Lazy.Captcha.Core.Storage; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Options; -namespace Lazy.Captcha.Core.Storeage +namespace Lazy.Captcha.Core.Storage { - public class DefaultStorage : IStorage + public class DefaultStorage(IOptionsMonitor options, IDistributedCache cache) : IStorage { - private readonly IDistributedCache _cache; - private readonly IOptionsMonitor _options; - - public DefaultStorage(IOptionsMonitor options, IDistributedCache cache) - { - _options = options; - _cache = cache; - } - private string WrapKey(string key) { - return $"{this._options.CurrentValue.StoreageKeyPrefix}{key}"; + return $"{options.CurrentValue.StorageKeyPrefix}{key}"; } public string Get(string key) { - return _cache.GetString(WrapKey(key)); + return cache.GetString(WrapKey(key)); } public void Remove(string key) { - _cache.Remove(WrapKey(key)); + cache.Remove(WrapKey(key)); } public void Set(string key, string value, DateTimeOffset absoluteExpiration) { - _cache.SetString(WrapKey(key), value, new DistributedCacheEntryOptions + cache.SetString(WrapKey(key), value, new DistributedCacheEntryOptions { AbsoluteExpiration = absoluteExpiration }); diff --git a/Lazy.Captcha.Core/Storage/MemeoryStorage.cs b/Lazy.Captcha.Core/Storage/MemoryStorage.cs similarity index 44% rename from Lazy.Captcha.Core/Storage/MemeoryStorage.cs rename to Lazy.Captcha.Core/Storage/MemoryStorage.cs index 6c84cb704d0e04078bae05ca2e8545a8122c63ca..28652a440428e3f8fffa3275ec03cd8951b24e7e 100644 --- a/Lazy.Captcha.Core/Storage/MemeoryStorage.cs +++ b/Lazy.Captcha.Core/Storage/MemoryStorage.cs @@ -5,34 +5,36 @@ using System.Text; namespace Lazy.Captcha.Core.Storage { - public class MemeoryStorage : IStorage + public class MemoryStorage : IStorage { - private MemoryCache Cache; - public string StoreageKeyPrefix { get; set; } = string.Empty; + private readonly MemoryCache _cache = MemoryCache.Default; + public string StorageKeyPrefix { get; set; } = string.Empty; - public MemeoryStorage() + [Obsolete("由于拼写错误,已被废弃。请使用 `StorageKeyPrefix`。", false)] + public string StoreageKeyPrefix { - Cache = MemoryCache.Default; + get => StorageKeyPrefix; + set => StorageKeyPrefix = value; } private string WrapKey(string key) { - return $"{StoreageKeyPrefix}{key}"; + return $"{StorageKeyPrefix}{key}"; } public string Get(string key) { - return Cache.Get(WrapKey(key)); + return _cache.Get(WrapKey(key)); } public void Remove(string key) { - Cache.Remove(WrapKey(key)); + _cache.Remove(WrapKey(key)); } public void Set(string key, string value, DateTimeOffset absoluteExpiration) { - Cache.Set(WrapKey(key), value, absoluteExpiration); + _cache.Set(WrapKey(key), value, absoluteExpiration); } } } diff --git a/Lazy.Captcha.xUnit/Demo.cs b/Lazy.Captcha.xUnit/Demo.cs index d65e5a6f66ec3b02a968f519d59dcff061f60686..2c6116c358f5f34c3da70f2558dae34fbc3946b9 100644 --- a/Lazy.Captcha.xUnit/Demo.cs +++ b/Lazy.Captcha.xUnit/Demo.cs @@ -33,7 +33,7 @@ namespace Lazy.Captcha.xUnit [InlineData("#FF000088")] [InlineData("#00FF0088")] [InlineData("#0000FF88")] - [Trait("SixLabors", "SixLabors")] + [Trait("SixLabors工具", "SixLabors")] public void GenerateCaptcha_Test(string color) { //var outputFileName = System.IO.Path.Combine(OutputPath, $"cc2_{color}.png"); @@ -48,7 +48,7 @@ namespace Lazy.Captcha.xUnit //} //var fileExists = File.Exists(outputFileName); - //_outputHelper.WriteLine(fileExists ? "ļ" : "ļ"); + //_outputHelper.WriteLine(fileExists ? "文件存在" : "文件不存在"); //Assert.True(fileExists); } } diff --git a/README.md b/README.md index f9e2b431caeb3a1aa6da84c1247e5295bf79936e..ba63cc1b134af0a4e33cf34495687a994b828911 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ builder.Services.AddCaptcha(builder.Configuration); "CodeLength": 4, // 验证码长度, 要放在CaptchaType设置后 当类型为算术表达式时,长度代表操作的个数, 例如2 "ExpirySeconds": 60, // 验证码过期秒数 "IgnoreCase": true, // 比较时是否忽略大小写 - "StoreageKeyPrefix": "", // 存储键前缀 + "StorageKeyPrefix": "", // 存储键前缀 "RateLimit": { "Enabled": false, // 是否启用频率限制 "WindowSeconds": 60, // 时间窗口(秒) @@ -136,12 +136,11 @@ builder.Services.AddCaptcha(builder.Configuration); ``` c# // 全部配置 builder.Services.AddCaptcha(builder.Configuration, option => -{ option.CaptchaType = CaptchaType.WORD; // 验证码类型 option.CodeLength = 6; // 验证码长度, 要放在CaptchaType设置后. 当类型为算术表达式时,长度代表操作的个数 option.ExpirySeconds = 30; // 验证码过期时间 option.IgnoreCase = true; // 比较时是否忽略大小写 - option.StoreageKeyPrefix = ""; // 存储键前缀 + option.StorageKeyPrefix = ""; // 存储键前缀 option.ImageOption.Animation = true; // 是否启用动画 option.ImageOption.FrameDelay = 30; // 每帧延迟,Animation=true时有效, 默认30 diff --git a/Sample.MvcFramework/Global.asax.cs b/Sample.MvcFramework/Global.asax.cs index 9ac5e736d50a276ac8bd472502a7b45168c193d5..7034b72671e411802e9fe9ed97d79023a429c8d6 100644 --- a/Sample.MvcFramework/Global.asax.cs +++ b/Sample.MvcFramework/Global.asax.cs @@ -31,7 +31,7 @@ namespace Sample.MvcFramework .Height(35) .FontSize(20) .CaptchaType(CaptchaType.ARITHMETIC) - .FontFamily(DefaultFontFamilys.Instance.Ransom) + .FontFamily(DefaultFontFamilies.Instance.Ransom) .InterferenceLineCount(3) .Animation(false) .Build(); diff --git a/Sample.NetCore/Controllers/CaptchaController.cs b/Sample.NetCore/Controllers/CaptchaController.cs index 29cd61ff9fd98c0f977f97d1ee735dd1c771828d..decd6889d3cca7d3d0cc70ccdaf9fc098c6731e9 100644 --- a/Sample.NetCore/Controllers/CaptchaController.cs +++ b/Sample.NetCore/Controllers/CaptchaController.cs @@ -131,7 +131,7 @@ namespace Sample.NetCore.Controllers .Height(35) .FontSize(26) .CaptchaType(Enum.Parse(type)) - .FontFamily(DefaultFontFamilys.Instance.GetFontFamily(font)) + .FontFamily(DefaultFontFamilies.Instance.GetFontFamily(font)) .InterferenceLineCount(2) .Animation(false) .TextBold(textBold) diff --git a/Sample.NetCore/RandomCaptcha.cs b/Sample.NetCore/RandomCaptcha.cs index c6800d95dcb4c386a8229d60cf60df731acf9618..91ff3046151d927b370c331533d8df9f5d9a963b 100644 --- a/Sample.NetCore/RandomCaptcha.cs +++ b/Sample.NetCore/RandomCaptcha.cs @@ -39,12 +39,12 @@ namespace Sample.NetCore // 如果包含中文时,使用kaiti字体,否则文字乱码 if (options.CaptchaType.ContainsChinese()) { - options.ImageOption.FontFamily = DefaultFontFamilys.Instance.Kaiti; + options.ImageOption.FontFamily = DefaultFontFamilies.Instance.Kaiti; options.ImageOption.FontSize = 24; } else { - options.ImageOption.FontFamily = DefaultFontFamilys.Instance.Actionj; + options.ImageOption.FontFamily = DefaultFontFamilies.Instance.Actionj; } // 动静随机 diff --git a/Sample.Winfrom/OptionProviders/FontFamilyOptionProvider.cs b/Sample.Winfrom/OptionProviders/FontFamilyOptionProvider.cs index 5ef5c489731a19ee83e7cf0f342a79d3c75d884a..c883fd19801441da66f458d826943602d62edbe9 100644 --- a/Sample.Winfrom/OptionProviders/FontFamilyOptionProvider.cs +++ b/Sample.Winfrom/OptionProviders/FontFamilyOptionProvider.cs @@ -14,17 +14,17 @@ namespace Sample.Winfrom.OptionProviders { return new List { - new FontFamilyOption("Actionj", DefaultFontFamilys.Instance.Actionj), - new FontFamilyOption("Kaiti", DefaultFontFamilys.Instance.Kaiti), - new FontFamilyOption("Fresnel", DefaultFontFamilys.Instance.Fresnel), - new FontFamilyOption("Prefix", DefaultFontFamilys.Instance.Prefix), - new FontFamilyOption("Ransom", DefaultFontFamilys.Instance.Ransom), - new FontFamilyOption("Scandal", DefaultFontFamilys.Instance.Scandal), - new FontFamilyOption("Epilog", DefaultFontFamilys.Instance.Epilog), - new FontFamilyOption("Headache", DefaultFontFamilys.Instance.Headache), - new FontFamilyOption("Lexo", DefaultFontFamilys.Instance.Lexo), - new FontFamilyOption("Progbot", DefaultFontFamilys.Instance.Progbot), - new FontFamilyOption("Robot", DefaultFontFamilys.Instance.Robot), + new FontFamilyOption("Actionj", DefaultFontFamilies.Instance.Actionj), + new FontFamilyOption("Kaiti", DefaultFontFamilies.Instance.Kaiti), + new FontFamilyOption("Fresnel", DefaultFontFamilies.Instance.Fresnel), + new FontFamilyOption("Prefix", DefaultFontFamilies.Instance.Prefix), + new FontFamilyOption("Ransom", DefaultFontFamilies.Instance.Ransom), + new FontFamilyOption("Scandal", DefaultFontFamilies.Instance.Scandal), + new FontFamilyOption("Epilog", DefaultFontFamilies.Instance.Epilog), + new FontFamilyOption("Headache", DefaultFontFamilies.Instance.Headache), + new FontFamilyOption("Lexo", DefaultFontFamilies.Instance.Lexo), + new FontFamilyOption("Progbot", DefaultFontFamilies.Instance.Progbot), + new FontFamilyOption("Robot", DefaultFontFamilies.Instance.Robot), }; } }