mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-12 19:35:50 +00:00
feat: 邮箱验证部分
This commit is contained in:
parent
d9b9c0f42c
commit
68f5b30f7d
@ -3,12 +3,17 @@
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\UserEmailVerification;
|
||||
use App\Module\Base;
|
||||
use Arr;
|
||||
use Cache;
|
||||
use Captcha;
|
||||
use Carbon\Carbon;
|
||||
use Config;
|
||||
use Mail;
|
||||
use Request;
|
||||
use Exception;
|
||||
use Validator;
|
||||
|
||||
/**
|
||||
* @apiDefine users
|
||||
@ -53,6 +58,10 @@ class UsersController extends AbstractController
|
||||
}
|
||||
}
|
||||
$user = User::reg($email, $password);
|
||||
$isRegVerify = false;//Base::settingFind('emailSetting', 'reg_verify') === 'open' ? true : false;
|
||||
if ($isRegVerify) {
|
||||
UserEmailVerification::userEmailSend($user);
|
||||
}
|
||||
} else {
|
||||
$needCode = !Base::isError(User::needCode($email));
|
||||
if ($needCode) {
|
||||
@ -559,4 +568,53 @@ class UsersController extends AbstractController
|
||||
//
|
||||
return Base::retSuccess('修改成功', $userInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/email/verification 13. 邮箱验证
|
||||
*
|
||||
* @apiDescription 不需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup users
|
||||
* @apiName email__verification
|
||||
*
|
||||
* @apiParam {String} code 验证参数
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据(同"获取我的信息"接口)
|
||||
*/
|
||||
public function email__verification()
|
||||
{
|
||||
$data = Request::input();
|
||||
// 表单验证
|
||||
$validator = Validator::make($data, [
|
||||
"code" => ["required"],
|
||||
], [
|
||||
"code.required" => "required字段非法",
|
||||
]);
|
||||
if ($validator->fails())
|
||||
return Base::retError($validator->errors()->first());
|
||||
$res = UserEmailVerification::where('code', $data['code'])->first();
|
||||
if (empty($res)) {
|
||||
return Base::retError('链接已失效');
|
||||
}
|
||||
// 如果已经校验过
|
||||
if (intval($res->status) === 1)
|
||||
return Base::retError('链接已经使用过');
|
||||
|
||||
$oldTime = strtotime($res->created_at);
|
||||
$time = time();
|
||||
//24个小时失效
|
||||
if (abs($time - $oldTime) > 86400) {
|
||||
return Base::retError("链接已失效");
|
||||
}
|
||||
UserEmailVerification::where('code', $data['code'])
|
||||
->update([
|
||||
'status' => 1
|
||||
]);
|
||||
User::where('userid', $res->userid)->update([
|
||||
'is_email_verity' => 1
|
||||
]);
|
||||
return Base::retSuccess('绑定邮箱成功');
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ use Carbon\Carbon;
|
||||
* @property int|null $task_dialog_id 最后打开的任务会话ID
|
||||
* @property string|null $created_ip 注册IP
|
||||
* @property string|null $disable_at 禁用时间
|
||||
* @property int $is_email_verity 邮箱是否已验证
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Database\Factories\UserFactory factory(...$parameters)
|
||||
@ -43,6 +44,7 @@ use Carbon\Carbon;
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User whereEmail($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User whereEncrypt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User whereIdentity($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User whereIsEmailVerity($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User whereLastAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User whereLastIp($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User whereLineAt($value)
|
||||
|
||||
69
app/Models/UserEmailVerification.php
Normal file
69
app/Models/UserEmailVerification.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use App\Module\Base;
|
||||
use Config;
|
||||
use Exception;
|
||||
use Mail;
|
||||
|
||||
/**
|
||||
* App\Models\UserEmailVerification
|
||||
*
|
||||
* @property int $id
|
||||
* @property int $userid 用户id
|
||||
* @property string $code 验证参数
|
||||
* @property string $email 电子邮箱
|
||||
* @property string $status 0-未验证,1-已验证
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocket newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocket newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocket query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocket whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocket whereCode($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocket whereEmail($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocket whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocket whereStatus($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocket whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocket whereUserid($value)
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class UserEmailVerification extends AbstractModel
|
||||
{
|
||||
|
||||
/**
|
||||
* 发验证邮箱
|
||||
* @param User $user
|
||||
*/
|
||||
public static function userEmailSend(User $user)
|
||||
{
|
||||
//删除
|
||||
self::where('userid', $user->userid)->delete();
|
||||
$info['created_at'] = date("Y-m-d H:i:s");
|
||||
$info['userid'] = $user->userid;
|
||||
$info['email'] = $user->email;
|
||||
$info['code'] = md5(uniqid(md5(microtime(true)), true)) . md5($user->userid . md5('lddsgagsgkdiid' . microtime(true)));
|
||||
$url = Base::fillUrl('valid/email') . '?code=' . $info['code'];
|
||||
$info['status'] = 0;
|
||||
$userEmailVerification = self::createInstance($info);
|
||||
$userEmailVerification->save();
|
||||
try {
|
||||
// 15秒后超时
|
||||
Mail::send('email', ['url' => $url], function ($m) use ($user) {
|
||||
$m->from(Base::settingFind('emailSetting', 'account') ?? Config::get("mail.mailers.smtp.username"), env('APP_NAME'));
|
||||
$m->to($user->email);
|
||||
$m->subject("绑定邮箱验证");
|
||||
});
|
||||
} catch (Exception $exception) {
|
||||
// 一般是请求超时
|
||||
if (strpos($exception->getMessage(), "Timed Out") !== false)
|
||||
throw new ApiException("language.TimedOut");
|
||||
else
|
||||
throw new ApiException($exception->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8,6 +8,7 @@ namespace App\Models;
|
||||
* @property int $id
|
||||
* @property int|null $dialog_id 对话ID
|
||||
* @property int|null $userid 会员ID
|
||||
* @property int|null $top 是否置顶:0否,1是
|
||||
* @property string|null $top_at 置顶时间
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
@ -17,6 +18,7 @@ namespace App\Models;
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereDialogId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereTop($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereTopAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereUserid($value)
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddIsEmailVerityToUsers extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->boolean('is_email_verity')->default(0)->nullable(false)->after('disable_at')->comment('邮箱是否已验证');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn("is_email_verity");
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateUserEmailVerificationsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('user_email_verifications', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->integer('userid')->nullable()->default(0)->comment('用户id');
|
||||
$table->string('code')->nullable()->default('')->comment('验证参数');
|
||||
$table->string('email')->nullable()->default('')->comment('电子邮箱');
|
||||
$table->integer('status')->nullable()->default(0)->comment('0-未验证,1-已验证');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('user_email_verifications');
|
||||
}
|
||||
}
|
||||
84
resources/assets/js/pages/email/validEmail.vue
Normal file
84
resources/assets/js/pages/email/validEmail.vue
Normal file
@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<div class="valid-wrap">
|
||||
<div class="valid-box">
|
||||
<div class="valid-title">{{$L('验证邮箱')}}</div>
|
||||
<Spin size="large" v-if="!success && !error"></Spin>
|
||||
<div class="validation-text" v-if="success">
|
||||
<p>{{$L('您的邮箱已通过验证')}}</p>
|
||||
<p>{{$L('今后您可以通过此邮箱重置您的账号密码')}}</p>
|
||||
</div>
|
||||
<div class="validation-text" v-if="error">
|
||||
<div>{{$L('您的邮箱未通过验证,可能的原因:')}}</div>
|
||||
<div>{{$L('1.验证码已过期')}}</div>
|
||||
<div>{{$L('2.重复使用验证码')}}</div>
|
||||
</div>
|
||||
<div slot="footer" v-if="success">
|
||||
<Button type="primary" @click="$A.userLogoutV2()" long>{{$L('返回首页')}}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "validEmail",
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
success: false,
|
||||
error: false,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.verificationEmail();
|
||||
},
|
||||
watch: {},
|
||||
methods: {
|
||||
verificationEmail() {
|
||||
this.$store
|
||||
.dispatch("call", {
|
||||
url: "users/email/verification",
|
||||
data: {
|
||||
code: this.$route.query.code
|
||||
}
|
||||
})
|
||||
.then(({data}) => {
|
||||
this.success = true;
|
||||
this.error = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.success = false;
|
||||
this.error = true;
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.valid-wrap {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.valid-box {
|
||||
width: 500px;
|
||||
background-color: #fff;
|
||||
padding: 5px 15px 20px 15px;
|
||||
border-radius: 10px;
|
||||
|
||||
.valid-title {
|
||||
border-bottom: 1px solid #e8eaec;
|
||||
padding: 14px 16px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.validation-text{
|
||||
padding: 10px;
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
6
resources/assets/js/routes.js
vendored
6
resources/assets/js/routes.js
vendored
@ -100,4 +100,10 @@ export default [
|
||||
path: '*',
|
||||
component: () => import('./pages/404.vue')
|
||||
},
|
||||
{
|
||||
name: 'validEmail',
|
||||
path: '/valid/email',
|
||||
meta: {title: '验证绑定邮箱'},
|
||||
component: () => import('./pages/email/validEmail.vue')
|
||||
},
|
||||
]
|
||||
|
||||
15
resources/views/email.blade.php
Normal file
15
resources/views/email.blade.php
Normal file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ app()->getLocale() }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
你好,你正在绑定 {{env('APP_NAME') }} 的邮箱,请于24小时之内点击该链接完成验证 :
|
||||
<div style="display: flex; justify-content: center;">
|
||||
<a href="{{$url}}">{{$url}}</a>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
<body>
|
||||
Loading…
x
Reference in New Issue
Block a user