上节编写了滑动验证码的基本设置与缓存编写,缓存的目的是为了更快的加载滑动验证码的背景图、滑块图与凹槽图,本节我们来根据预设的模板,获取前端需要背景图,滑块图与凹槽图。
上一节内容:.NET 6 实现滑动验证码(五)、验证码设置与缓存
这次只获取到这些资源,下一节介绍根据获取回来的背景图、滑块图与凹槽图,实现在背景图上叠加凹槽图,在滑块图上叠加凹槽图的那部分背景内容。
注意:背景图需要在项目中的appsettings.json中进行设置,如果在appsettings.json中没设置滑块与凹槽图片。则读取默认图。默认图在templates目录下,其中文件夹1-5是滑块验证码的背景图与凹槽图。文件夹6是旋转验证码的背景图与凹槽图。appsettings.json的设置在后面介绍
获取滑动验证码背景图、滑块图与凹槽图
随机获取背景图、滑块图与凹槽图。
在Resources目录下,新建DefaultResourceManager.cs,用来获取验证码的背景图片、滑块图与凹槽图。
注意:滑块图与凹槽图是需要成对出现的。也就是说滑块图与凹槽图轮廓应该是一致的
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using SlideCaptcha.Exceptions;
using SlideCaptcha.Interface;
using SlideCaptcha.Model;
namespace SlideCaptcha.Resources
{
public class DefaultResourceManager : IResourceManager
{
private readonly Random _random = new Random();
private readonly IResourceHandlerManager _resourceProviderManager;
private readonly List<Resource> _backgrounds = new List<Resource>();
private readonly List<TemplatePair> _templates = new List<TemplatePair>();
public DefaultResourceManager(IEnumerable<IResourceProvider> resourceProviders, IResourceHandlerManager resourceProviderManager)
{
_resourceProviderManager = resourceProviderManager;
foreach (var provider in resourceProviders)
{
_backgrounds.AddRange(provider.Backgrounds());
_templates.AddRange(provider.Templates());
}
}
/// <summary>
/// 随机获取验证码背景图
/// </summary>
/// <returns></returns>
/// <exception cref="SlideCaptchaException"></exception>
public async Task<byte[]> RandomBackground()
{
if (_backgrounds.Count == 0) throw new SlideCaptchaException("背景图不能为空");
var background = _backgrounds[_random.Next(_backgrounds.Count)];
return await _resourceProviderManager.Handle(background);
}
/// <summary>
/// 随机获取预设的滑块图与凹槽图
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
/// <exception cref="SlideCaptchaException"></exception>
public async Task<(byte[], byte[])> RandomTemplate(string type)
{
if (_templates.Count == 0) throw new SlideCaptchaException("模板不能为空");
var template_list = _templates.Where(t => t.TYPE.Equals(type, StringComparison.OrdinalIgnoreCase)).ToList();
if (!template_list.Any()) throw new SlideCaptchaException("模板为空");
var template = template_list[_random.Next(template_list.Count)];
var notch = await _resourceProviderManager.Handle(template.Notch);
var slider = await _resourceProviderManager.Handle(template.Slider);
return (slider, notch);
}
}
}
获取templates目录下的嵌入资源
templates 存放着默认的5个滑块与凹槽图资源,1个旋转与凹槽资源。
在Resources下建一个Provider目录。Provider目录下新建一个EmbeddedResourceProvider.cs。编写代码:
using SlideCaptcha.Constant;
using SlideCaptcha.Interface;
using SlideCaptcha.Model;
using SlideCaptcha.Resources.Handler;
using System.Collections.Generic;
namespace SlideCaptcha.Resources.Provider
{
/// <summary>
/// 嵌入资源的滑块图与凹槽图获取
/// 嵌入资源在templates目录中,没有背景图资源,只有滑块与凹槽图的资源
/// </summary>
public class EmbeddedResourceProvider : IResourceProvider
{
/// <summary>
/// 由于嵌入资源没有背景图,直接返回
/// </summary>
/// <returns></returns>
public List<Resource> Backgrounds()
{
return new List<Resource>();
}
/// <summary>
/// 返回滑动验证码默认的模板(滑块与凹槽。成对出现)
/// 返回旋转验证码默认的模板(旋转块与凹槽。成对出现)
/// </summary>
/// <returns></returns>
public List<TemplatePair> Templates()
{
var templatePairs = new List<TemplatePair>();
//滑动验证码默认模板
for (var i = 0; i < 5; i++)
{
var sliderResourceName = $"SlideCaptcha.templates._{i + 1}.slider.png";
var notchResourceName = $"SlideCaptcha.templates._{i + 1}.notch.png";
var sliderResource = new Resource(EmbeddedResourceHandler.TYPE, sliderResourceName);
var notchResource = new Resource(EmbeddedResourceHandler.TYPE, notchResourceName);
templatePairs.Add(TemplatePair.Create(sliderResource, notchResource, CaptchaTypeConstant.SLIDER));
}
//旋转验证码默认模板
var rotateSliderResourceName = $"SlideCaptcha.templates._6.active.png";
var rotateNotchResourceName = $"SlideCaptcha.templates._6.fixed.png";
var rotateSliderResource = new Resource(EmbeddedResourceHandler.TYPE, rotateSliderResourceName);
var rotateNotchResource = new Resource(EmbeddedResourceHandler.TYPE, rotateNotchResourceName);
templatePairs.Add(TemplatePair.Create(rotateSliderResource, rotateNotchResource, CaptchaTypeConstant.ROTATE));
return templatePairs;
}
}
}
获取配置文件中配置节的资源
代码可以获取appsettings.json配置节的图片资源。配置节后面介绍。
using Microsoft.Extensions.Options;
using SlideCaptcha.Constant;
using SlideCaptcha.Interface;
using SlideCaptcha.Model;
using System.Collections.Generic;
namespace SlideCaptcha.Resources.Provider
{
/// <summary>
/// 根据配置获取背景图、滑块图与凹槽图。
/// 配置节在appsettings.json中
/// </summary>
public class OptionsResourceProvider : IResourceProvider
{
private readonly List<Resource> _backgrounds = new List<Resource>();
private readonly List<TemplatePair> _templates = new List<TemplatePair>();
/// <summary>
/// 构造函数,如果Backgrounds
/// </summary>
/// <param name="optionAccessor"></param>
public OptionsResourceProvider(IOptionsMonitor<CaptchaOptions> optionAccessor)
{
var options = optionAccessor.CurrentValue;
if (options.Backgrounds != null)
{
_backgrounds.AddRange(options.Backgrounds);
}
if (options.Templates != null)
{
_templates.AddRange(options.Templates);
}
}
/// <summary>
/// 返回背景图
/// </summary>
/// <returns></returns>
public List<Resource> Backgrounds()
{
return _backgrounds;
}
/// <summary>
/// 返回滑块,凹槽图
/// </summary>
/// <returns></returns>
public List<TemplatePair> Templates()
{
return _templates;
}
}
}
代码中,在构造函数判断如果Backgrounds或Templates节点不空,则添加资源。
获取图片的Bytes数据
我们获取到图片Bytes数据后,交由验证码生成功能,将Bytes转换为SixLabors.ImageSharp
中的Image<TPixel>
类型,然后进行图片的操作。
首先:在Resources目录下新建Handler目录。
获取缓存中验证码图片数据
在Handler目录中新建CachedResourceHandlerManager.cs。代码如下:
using SlideCaptcha.Exceptions;
using SlideCaptcha.Interface;
using SlideCaptcha.Model;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace SlideCaptcha.Resources.Handler
{
internal class CachedResourceHandlerManager : IResourceHandlerManager
{
private IEnumerable<IResourceHandler> _resourceHandlers;
private Dictionary<Resource, byte[]> _cache = new Dictionary<Resource, byte[]>();
public CachedResourceHandlerManager(IEnumerable<IResourceHandler> resourceHandlers)
{
_resourceHandlers = resourceHandlers;
}
/// <summary>
/// 异步返回缓存中的验证码图片
/// </summary>
public async Task<byte[]> Handle(Resource resource)
{
if (resource == null) throw new ArgumentNullException(nameof(resource));
if (_cache.ContainsKey(resource))
{
return _cache[resource];
}
foreach (var provider in _resourceHandlers)
{
if (provider.CanHandle(resource.Type))
{
var bytes = await provider.Handle(resource);
_cache.Add(resource, bytes);
return bytes;
}
}
throw new SlideCaptchaException("没有可用的资源提供者!");
}
}
}
获取嵌入资源的数据
获取templates目录下的图片文件Bytes数据。
using SlideCaptcha.Interface;
using SlideCaptcha.Model;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
namespace SlideCaptcha.Resources.Handler
{
public class EmbeddedResourceHandler : IResourceHandler
{
public const string TYPE = "embedded";
public bool CanHandle(string handlerType)
{
return handlerType == TYPE;
}
public async Task<byte[]> Handle(Resource resource)
{
var assembly = Assembly.GetExecutingAssembly();
var stream = assembly.GetManifestResourceStream(resource.Data);
return await StreamToBytes(stream);
}
private async Task<byte[]> StreamToBytes(Stream stream)
{
byte[] bytes = new byte[stream.Length];
await stream.ReadAsync(bytes, 0, bytes.Length);
// 设置当前流的位置为流的开始
stream.Seek(0, SeekOrigin.Begin);
return bytes;
}
}
}
获取指定文件的Bytes数据
文件的Bytes数据一般在配置文件中进行了配置,然后读取自定义目录中的图片文件的Bytes数据。
using SlideCaptcha.Interface;
using SlideCaptcha.Model;
using System;
using System.IO;
using System.Threading.Tasks;
namespace SlideCaptcha.Resources.Handler
{
public class FileResourceHandler : IResourceHandler
{
public const string TYPE = "file";
public bool CanHandle(string handlerType)
{
return handlerType == TYPE;
}
public async Task<byte[]> Handle(Resource resource)
{
if (resource == null) throw new ArgumentNullException(nameof(resource));
return await File.ReadAllBytesAsync(resource.Data);
}
}
}
有了这些内容,下一节实现验证码图片的生成操作。
下载方式:
点击下方公众号卡片,关注我,回复captcha
免费领取!