顾客找回密码功能

This commit is contained in:
TL 2022-07-07 15:54:33 +08:00
parent 2e577bbd8c
commit 6ee3aacc0f
11 changed files with 341 additions and 4 deletions

View File

@ -0,0 +1,28 @@
<?php
/**
* Notification.php
*
* @copyright 2022 opencart.cn - All Rights Reserved
* @link http://www.guangdawangluo.com
* @author TL <mengwb@opencart.cn>
* @created 2022-07-07 10:52:57
* @modified 2022-07-07 10:52:57
*/
namespace Beike\Libraries;
class Notification
{
/**
* @param string $code
* @param string $message
* @param string $type email|telephone
* @return bool
*/
public static function verifyCode(string $code, string $message, string $type): bool
{
return true;
}
}

View File

@ -0,0 +1,25 @@
<?php
/**
* VerifyCode.php
*
* @copyright 2022 opencart.cn - All Rights Reserved
* @link http://www.guangdawangluo.com
* @author Edward Yang <yangjin@opencart.cn>
* @created 2022-07-07 15:22:18
* @modified 2022-07-07 15:22:18
*/
namespace Beike\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
class VerifyCode extends Model
{
use HasFactory;
use SoftDeletes;
protected $fillable = ['account', 'code'];
}

View File

@ -28,16 +28,24 @@ class CustomerRepo
}
/**
* @param $id
* @param $customer
* @param $data
* @return bool|int
*/
public static function update($id, $data)
public static function update($customer, $data)
{
if (!$customer instanceof Customer) {
$customer = Customer::query()->findOrFail($customer);
}
if (isset($data['password'])) {
$data['password'] = Hash::make($data['password']);
}
return Customer::query()->find($id)->update($data);
return $customer->update($data);
}
public static function findByEmail($email)
{
return Customer::query()->where('email', $email)->first();
}
/**

View File

@ -0,0 +1,55 @@
<?php
/**
* VerifyCodeRepo.php
*
* @copyright 2022 opencart.cn - All Rights Reserved
* @link http://www.guangdawangluo.com
* @author Edward Yang <yangjin@opencart.cn>
* @created 2022-07-07 15:22:05
* @modified 2022-07-07 15:22:05
*/
namespace Beike\Repositories;
use Beike\Models\VerifyCode;
class VerifyCodeRepo
{
/**
* 创建一个记录
* @param $data
* @return int
*/
public static function create($data)
{
$verifyCode = VerifyCode::query()->create($data);
return $verifyCode;
}
/**
* @param $id
* @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Model|null
*/
public static function find($id)
{
return VerifyCode::query()->find($id);
}
public static function findByAccount($account)
{
return VerifyCode::query()->where('account', $account)->first();
}
/**
* @param $id
* @return void
*/
public static function delete($id)
{
$verifyCode = VerifyCode::query()->find($id);
if ($verifyCode) {
$verifyCode->delete();
}
}
}

View File

@ -0,0 +1,50 @@
<?php
/**
* ForgottenController.php
*
* @copyright 2022 opencart.cn - All Rights Reserved
* @link http://www.guangdawangluo.com
* @author TL <mengwb@opencart.cn>
* @created 2022-07-06 15:39:08
* @modified 2022-07-06 15:39:08
*/
namespace Beike\Shop\Http\Controllers\Account;
use Beike\Shop\Services\AccountService;
use Illuminate\Http\Request;
class ForgottenController
{
/**
* 找回密码页面
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
*/
public function index()
{
return view('account/forgotten');
}
/**
* 接收email地址生成验证码发送到邮件地址
* @param Request $request
* @return array
*/
public function sendVerifyCode(Request $request)
{
AccountService::sendVerifyCodeForForgotten($request->get('email'), 'email');
return json_success('验证码已发送,请查看并输入验证码');
}
/**
* 接收验证码和新密码、确认密码,验证验证码是否正确、密码和确认密码是否相等,然后修改密码
* @param Request $request
* @return array
*/
public function changePassword(ForgottenRequest $request)
{
AccountService::verifyAndChangePassword($request->get('code'), $request->get('account'), $request->get('password'));
return json_success('密码已修改');
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace Beike\Shop\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ForgottenRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'password' => 'required|confirmed',
];
}
public function attributes()
{
return [
'password' => '密码'
];
}
}

View File

@ -2,6 +2,7 @@
use Beike\Models\Customer;
use Beike\Shop\Http\Controllers\Account\AddressController;
use Beike\Shop\Http\Controllers\Account\ForgottenController;
use Beike\Shop\Http\Controllers\Account\OrderController;
use Beike\Shop\Http\Controllers\ZoneController;
use Illuminate\Support\Facades\Route;
@ -40,6 +41,9 @@ Route::prefix('/')
Route::get('register', [RegisterController::class, 'index'])->name('register.index');
Route::post('register', [RegisterController::class, 'store'])->name('register.store');
Route::get('logout', [LogoutController::class, 'index'])->name('logout');
Route::get('forgotten', [ForgottenController::class, 'index'])->name('forgotten.index');
Route::post('forgotten/send_code', [ForgottenController::class, 'sendVerifyCode'])->name('forgotten.send_code');
Route::post('forgotten/password', [ForgottenController::class, 'changePassword'])->name('forgotten.password');
Route::resource('countries.zones', ZoneController::class);
Route::middleware('shop_auth:' . Customer::AUTH_GUARD)

View File

@ -12,9 +12,13 @@
namespace Beike\Shop\Services;
use Beike\Libraries\Notification;
use Beike\Models\Customer;
use Beike\Repositories\CustomerRepo;
use Beike\Repositories\VerifyCodeRepo;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
class AccountService
{
@ -38,4 +42,54 @@ class AccountService
return CustomerRepo::create($data);
}
/**
* 发送验证码通过$type方式type为email或telephone
* @param $email
* @param $type
* @return void
*/
public static function sendVerifyCodeForForgotten($email, $type) {
$code = str_pad(mt_rand(10, 999999), 6, '0', STR_PAD_LEFT);
VerifyCodeRepo::create([
'account' => $email,
'code' => $code,
]);
Log::info("找回密码验证码:{$code}");
Notification::verifyCode($code, "您的验证码是%s,该验证码仅用于找回密码。", $type);
}
/**
* 验证验证码是否正确,并修改密码为新密码
* @param $code
* @param $account
* @param $password
* @param $type $account类型email代表$account为邮箱地址telephone代表$account为手机号码
* @return void
*/
public static function verifyAndChangePassword($code, $account, $password, $type = 'email')
{
$verifyCode = VerifyCodeRepo::findByAccount($account);
if ($verifyCode->created_at->addMinutes(10) < Carbon::now()) {
$verifyCode->delete();
throw new \Exception("您的验证码已过期10分钟请重新获取");
}
if ($verifyCode->code != $code) {
throw new \Exception("您的验证码错误");
}
if ($type == 'email') {
$customer = CustomerRepo::findByEmail($account);
} elseif ($type == 'telephone') {
throw new \Exception("暂不支持手机号码找回密码");
} else {
throw new \Exception("找回密码类型错误");
}
CustomerRepo::update($customer, ['password' => $password]);
}
}

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class VerifyCode extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('verify_codes', function (Blueprint $table) {
$table->id();
$table->string('account', 256);
$table->string('code', 16);
$table->softDeletes();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('verify_codes');
}
}

View File

@ -13,7 +13,7 @@
<div class="row">
<x-shop-sidebar/>
<x-hop-sidebars/>
<div class="col-12 col-md-9">
@if (\Session::has('success'))

View File

@ -0,0 +1,42 @@
@extends('layout.master')
@section('content')
<div class="container">
<h1>找回密码</h1>
<form action="{{ route('shop.register.store') }}" method="post">
@csrf
<div class="form-group">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text" id="email">邮箱</span>
</div>
<input type="text" name="register[email]" class="form-control" value="{{ old('register.email') }}" placeholder="邮箱地址">
</div>
@error('register.email')
<x-admin::form.error :message="$message"/>
@enderror
</div>
<div class="form-group">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text" id="password">密码</span>
</div>
<input type="password" name="register[password]" class="form-control" placeholder="密码">
</div>
@error('register.password')
<x-admin::form.error :message="$message"/>
@enderror
</div>
@if (session('error'))
<div class="alert alert-success">
{{ session('error') }}
</div>
@endif
<button type="submit" class="btn btn-primary btn-block mb-4">登录</button>
</form>
</div>
@endsection