微信小程序手机登录

微信小程序分别使用手机号微信登录
参考:

使用手机登录

发送手机短信

安装easy-sms

1
2
3
$ composer require "overtrue/easy-sms"
# config中添加easysms.php 配置文件
$ touch config/easysms.php

config.easysms.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
return [
// HTTP 请求的超时时间(秒)
'timeout' => 5.0,

// 默认发送配置
'default' => [
// 网关调用策略,默认:顺序调用
'strategy' => \Overtrue\EasySms\Strategies\OrderStrategy::class,

// 默认可用的发送网关
'gateways' => [
'qcloud',
],
],
// 可用的网关配置
'gateways' => [
'errorlog' => [
'file' => '/tmp/easy-sms.log',
],
'qcloud' => [
'sdk_app_id' => env('QCLOUD_APP_ID'), // SDK APP ID
'app_key' => env('QCLOUD_APP_KEY'), // APP KEY
'sign_name' => env('QCLOUD_APP_SIGN_NAME'), // 短信签名,如果使用默认签名,该字段可缺省(对应官方文档中的sign)
],
],
];

1
$ php artisan make:provider EasySmsServiceProvider

创建一个 ServiceProvider

app/providers/EasySmsServiceProvider.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Overtrue\EasySms\EasySms;

class EasySmsServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* @return void
*/
public function register()
{
$this->app->singleton(EasySms::class, function ($app) {
return new EasySms(config('easysms'));
});

$this->app->alias(EasySms::class, 'easysms');
}

/**
* Bootstrap services.
*
* @return void
*/
public function boot()
{
//
}
}

修改EasySmsServiceProvider.php

获取SDK AppID,App Key

腾讯云短信获取SDK AppID,App Key
注意:不同的应用有不同的AppID,App Key,要对应。调试时没有对应,导致发送失败。

.env

1
2
3
QCLOUD_APP_ID=
QCLOUD_APP_KEY=
QCLOUD_APP_SIGN_NAME=scottyun

发送短信

1
php artisan tinker

进入tinker

1
2
3
4
>> $sms = app('easysms');
>> $sms->send(13212345678, [
'content' => '【Lbbs社区】您的验证码是1234。如非本人操作,请忽略本短信',
]);

国内短信由签名+正文组成,【Lbbs社区】是短信签名;”您的验证码是{1}。如非本人操作,请忽略本短信”短信正文

修改数据结构

1
php artisan make:migration add_phone_to_users_table --table=users

database/migrations/{your_date}_add_phone_to_users_table.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddPhoneToUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('phone')->nullable()->unique()->after('name');
$table->string('email')->nullable()->change();
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('phone');
$table->string('email')->nullable(false)->change();
});
}
}
1
2
3
# 修改数据表的字段属性
$ composer require doctrine/dbal
$ php artisan migrate

短信验证码接口

1.输入手机号,手机短信验证码发送
2.填入短信验证码,验证是否成功
3.成功完成注册,创建用户

新建基类

1
$ php artisan make:controller Api/Controller

app/Http/Controllers/Api/Controller.php

1
2
3
4
5
6
7
8
9
10
11
<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller as BaseController;
use Dingo\Api\Routing\Helpers;

class Controller extends BaseController
{
use Helpers;
}

routes/api.php

1
2
3
4
5
6
7
8
9
10
11
12
<?php

use Illuminate\Http\Request;
$api = app('Dingo\Api\Routing\Router');

$api->version('v1', [
'namespace' => 'App\Http\Controllers\Api'
], function($api) {
// 短信验证码
$api->post('verificationCodes', 'VerificationCodesController@store')
->name('api.verificationCodes.store');
});

创建验证类

1
2
3
$ php artisan make:request Api/VerificationCodeRequest
# 使用Dingo 的 FormRequest
$ php artisan make:request Api/FormRequest

app/Http/Requests/Api/FormRequest.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

namespace App\Http\Requests\Api;


use Dingo\Api\Http\FormRequest as BaseFormRequest;

class FormRequest extends BaseFormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
}

app/Http/Requests/Api/VerificationCodeRequest.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
//移除自带的 FormRequest
namespace App\Http\Requests\Api;

class VerificationCodeRequest extends FormRequest
{
public function rules()
{
return [
'phone' => [
'required',
'regex:/^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199)\d{8}$/',
'unique:users'
]
];
}
}

创建控制器

1
$ php artisan make:controller Api/VerificationCodesController

app/Http/Controllers/Api/VerificationCodesController.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php

namespace App\Http\Controllers\Api;

use App\Http\Requests\Api\VerificationCodeRequest;
use Overtrue\EasySms\EasySms;

class VerificationCodesController extends Controller
{
public function store(VerificationCodeRequest $request,EasySms $easySms)
{
$phone = $request->phone;
# 开发环境验证码1234
if (!app()->environment('production')) {
$code = '1234';
} else {
$code = str_pad(random_int(1, 9999), 4, 0, STR_PAD_LEFT);

try {
$easySms->send($phone, [
'content' => "【scottyun】larabbs短信验证码 {$code},不是本人请忽略"
]);
} catch (\Overtrue\EasySms\Exceptions\NoGatewayAvailableException $exception) {
$message = $exception->getException('qcloud')->getMessage();
return $this->response->errorInternal($message ?: '短信发送异常');
}
}

$key = 'verificationCode_' . \EasyWeChat\Kernel\Support\str_random(15);
$expiredAt = now()->addMinutes(10);

# 验证码10mins过期
\Cache::put($key, ['phone' => $phone, 'code' => $code], $expiredAt);

return $this->response->array([
'key' => $key,
'expired' => $expiredAt,
])->setStatusCode(201);
}
}
  • 生成四位随机码,用easysms发送
  • 验证码放入缓存有效期10 mins
  • 返回 key和过期时间,缓存中存储了phone ,code;和用户输入的验证码比对

用户注册接口

routes/api.php

1
2
3
4
5
6
7
8
9
10
11
12
<?php
...
$api->version('v1', [
'namespace' => 'App\Http\Controllers\Api'
], function($api) {
// 短信验证码
$api->post('verificationCodes', 'VerificationCodesController@store')
->name('api.verificationCodes.store');
// 用户注册
$api->post('users', 'UsersController@store')
->name('api.users.store');
});

创建控制器和验证类

1
2
$ php artisan make:controller Api/UsersController
$ php artisan make:request Api/UserRequest

app/Http/Requests/Api/UserRequest.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php

namespace App\Http\Requests\Api;

class UserRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|between:3,25|regex:/^[A-Za-z0-9\-\_]+$/|unique:users,name',
'password' => 'required|string|min:6',
'verification_key' => 'required|string',
'verification_code' => 'required|string',

];
}

public function attributes()
{
return [
'verification_key' => '短信验证码 key',
'verification_code' => '短信验证码',
];
}
}

用户注册提交的数据,name,password,verification_code。verification_key由$api->post(‘verificationCodes’, ‘VerificationCodesController@store’)产生。

app/Http/Controllers/Api/UsersController.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php

namespace App\Http\Controllers\Api;

use App\Http\Requests\Api\UserRequest;
use App\User;

class UsersController extends Controller
{
public function store(UserRequest $request)
{
$verifyData = \Cache::get($request->verification_key);

if (!$verifyData) {
//422 表示提交的参数错误
return $this->response->error('验证码已失效', 422);
}

if (!hash_equals($verifyData['code'], $request->verification_code)) {
return $this->response->errorUnauthorized('验证码错误');
}

$user = User::create([
'name' => $request->name,
'phone' => $request->phone,
'password' => bcrypt($request->password),
]);

//清空缓存
\Cache::forget($request->verification_key);

return $this->response->created();

}
}

判断验证码是否失效,再判断验证码是否正确。最后完成用户注册,清空缓存。

用户注册

图片验证码

短信验证码发送之前要输入验证码。

安装gregwar/captcha

1
$ composer require gregwar/captcha

routes/api.php

1
2
3
// 图片验证码
$api->post('captchas', 'CaptchasController@store')
->name('api.captchas.store');

创建控制器和验证类

1
2
$ php artisan make:controller Api/CaptchasController
$ php artisan make:request Api/CaptchaRequest

app/Http/Requests/Api/CaptchaRequest.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

namespace App\Http\Requests\Api;


class CaptchaRequest extends FormRequest
{

/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'phone' => [
'required',
'regex:/^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199)\d{8}$/',
'unique:users'
]
];
}
}

app/Http/Controllers/Api/CaptchasController.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php

namespace App\Http\Controllers\Api;

use App\Http\Requests\Api\CaptchaRequest;
use Gregwar\Captcha\CaptchaBuilder;

class CaptchasController extends Controller
{
public function store(CaptchaRequest $request,CaptchaBuilder $captchaBuilder)
{
$key = 'captcha-'.\EasyWeChat\Kernel\Support\str_random(15);
$phone = $request->phone;

$captcha = $captchaBuilder->build();
$expiredAt = now()->addMinutes(2);
\Cache::put($key,['phone' => $phone,'code' => $captcha->getPhrase()],$expiredAt);

$result = [
'captcha_key' => $key,
'expired_at' => $expiredAt,
'captcha_image_content' => $captcha->inline(),
];

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

生成验证码,和phone 一起存入缓存中。返回key,过期时间,给用户看到的验证码图片。


注册码生成

修改短信验证码接口

app/Http/Requests/Api/VerificationCodeRequest.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php

namespace App\Http\Requests\Api;

class VerificationCodeRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'captcha_key' => 'required|string',
'captcha_code' => 'required|string',
];
}

public function attributes()
{
return [
'captcha_key' => '图片验证码 key',
'captcha_code' => '图片验证码',
];
}
}

通过图片验证码验证是否发送短信给用户。

app/Http/Controllers/Api/VerificationCodesController.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?php

namespace App\Http\Controllers\Api;

use App\Http\Requests\Api\VerificationCodeRequest;
use Overtrue\EasySms\EasySms;

class VerificationCodesController extends Controller
{
public function store(VerificationCodeRequest $request,EasySms $easySms)
{
//catcha_key中存储 phone 和图片验证码文本
$captchaData = \Cache::get($request->captcha_key);
//验证码是否失效
if (!$captchaData) {
return $this->response->error('图片验证码已失效',422);
}
//验证码是否输入正确
if (!hash_equals($captchaData['code'],$request->captcha_code)) {
\Cache::forget($request->captcha_key);
return $this->response->errorUnauthorized('验证码错误');
}

$phone = $captchaData['phone'];

if (!app()->environment('production')) {
$code = '1234';
} else {
$code = str_pad(random_int(1, 9999), 4, 0, STR_PAD_LEFT);

try {
$easySms->send($phone, [
'content' => "【scottyun】larabbs短信验证码 {$code},不是本人请忽略"
]);
} catch (\Overtrue\EasySms\Exceptions\NoGatewayAvailableException $exception) {
$message = $exception->getException('qcloud')->getMessage();
return $this->response->errorInternal($message ?: '短信发送异常');
}
}

$key = 'verificationCode_' . \EasyWeChat\Kernel\Support\str_random(15);
$expiredAt = now()->addMinutes(10);

\Cache::put($key, ['phone' => $phone, 'code' => $code], $expiredAt);

return $this->response->array([
'key' => $key,
'expired' => $expiredAt->toDateString(),
])->setStatusCode(201);
}
}