使用 mews/captcha 实现 API 验证接口

本着代码洁癖,不想安装两个验证码依赖,看了一眼 @chaijiawei 的帖子,自己研究了一下,记录下来希望能帮助到其他同学。

/*
    app/Http/Controllers/Api/CaptchasController.php
*/

//  引用mews/captcha
use Mews\Captcha\Captcha;

class CaptchasController extends Controller
{
    public function store(CaptchaRequest $request, Captcha $captchaBuilder)
    {
    //  这里与教程不同,更改了缓存前缀,便于区分
        $key = 'cacheKey-'. Str::random(15);

    //  创建验证码 create(生成验证码方式,是否api接口)
        $captcha = $captchaBuilder->create('flat', true);
/*
        创建的验证码为数组格式:
        'sensitive' => $generator['sensitive'],
        'key' => $generator['key'], 
        最终显示图片
        'img' => data:image/png;base64... 
        key 通过hash算法用来匹配 img 显示的值,可以把 key 和 img 显示的值理解为一个键值对,后面使用 captcha_api_check() 方法来验证用户输入的验证码是否正确
*/
        $phone = $request->phone;
        $expiredAt = now()->addMinute(2);

        Cache::put($key, [
            'phone' => $phone,
    //      添加验证码生成的key到缓存中
            'captcha' => $captcha['key']
        ], $expiredAt);

        $result = [
            'cache_key' => $key,
            'expired_at' => $expiredAt->toDateTimeString(),
            // 此处与教程不同,多了一个key
            'captcha_key' => $captcha['key'],
            'captcha_img' => $captcha['img']
        ];

        return response()->json($result)->setStatusCode(201);
    }
}

在控制器中并没有像教程一样把生成的验证码存储到缓存中来和用户输入的验证码比较,而是把验证码生成的key键存储到了缓存中,后面与用户输入的验证码做键值匹配,即可验证用户输入的验证码是否正确。


先来测试一下我们的返回值:

一切正常,已经得到了我们想要的值,此处和教程一样,浏览器打开图片地址,并且记录下captcha_key的值,最好新开一个窗口来测试验证码的接口,便于填写,下面是验证码控制器部分。

/*
    app/Http/Controllers/Api/VerificationCodesController.php
*/
public function store(VerificationCodeRequest $request, EasySms $easySms)
    {
    //  这里将教程中的 captcha_key 换成了 cache_key 不要弄错
        $captchaData = Cache::get($request->cache_key);
        .
        .
        .
        // 使用captcha_api_check方法验证用户输入的验证码是否和我们缓存中记录的key相匹配,这里注意的是,判断的顺序不能错,前面的是用户输入的验证码,后面是缓存中记录的Key
        if(!captcha_api_check($request->captcha_code, $captchaData['captcha']))
        {
            Cache::forget($request->cache_key);
            throw new AuthenticationException('验证码错误');
        }
}

再来验证一下验证码接口,注意键名不要写错了。

看到验证码以通过,并生成了手机短信验证码的key


这里简单看一下captcha_api_check方法

    function captcha_api_check(string $value, string $key): bool
    {
    //  这里调用了mews/captcha的check_api方法
        return app('captcha')->check_api($value, $key);
    }

    public function check_api($value, $key): bool
    {
    //  这里调用了 Illuminate/Hashing/BcryptHasher 的check()方法
      return $this->hasher->check($value, $key);
    }  

我学的比较浅,才入门一个月。对laravel的框架了解还不多,源码也没怎么读过,理解的也不够深入,希望其他同学有看到的可以帮忙解答一下这里是怎么运算的。

悲观者永远正确,乐观者永远前行。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 1

今天又做了一遍,在验证这里遇到坑了 api_check 这个方法,需要在 captcha.php的配置文件中给bcrypt设置为true,否则key无法进行解密,用哈希匹配不了用户输入的验证码

'expire' => 120,
'encrypt' => true,
3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!