.NET 6 实现滑动验证码(六)、验证码背景图、滑块图与凹槽图的生成

上节编写了滑动验证码的基本设置与缓存编写,缓存的目的是为了更快的加载滑动验证码的背景图、滑块图与凹槽图,本节我们来根据预设的模板,获取前端需要背景图,滑块图与凹槽图。

上一节内容:.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 免费领取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

倾斜的水瓶座

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值