是否有内置方法可以从注册中删除帐户枚举?
Is there a built-in way to remove account enumeration from registration?
我使用 Jetstream 和 Inertia 创建了一个新站点。目前,该应用程序将 return 显示“电子邮件已被接收”。如果用户尝试使用现有电子邮件注册,则会收到消息。尽管进行了时序分析,但我还是希望将用户帐户的存在保密。有没有办法保持对电子邮件的唯一约束,但如果有人使用现有电子邮件注册,则显示相同的外在行为?理想情况下,我不想创建第二个用户,而是向现有用户发送电子邮件,建议他们重置密码或忽略该电子邮件。
我同意 Unflux 关于不更改此内容的意见,但如果您需要,您可以修改位于 app\Actions\Fortify\CreateNewUser.php
的 CreateNewUser.php
并更改验证消息或修改流程。
负责创建新用户的create()
方法如下所示:
public function create(array $input)
{
//define custom messages
$customValidationMessages = {
'email.unique' => 'New Message',
}
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], //email validation rules here
'password' => $this->passwordRules(),
], $customValidationMessages)->validate(); //add the variable containing the custom message(s) here
return User::create([
'name' => $input['name'],
'email' => $input['email'],
'password' => Hash::make($input['password']),
'api_token' => Str::random(60),
]);
}
如果您需要向用户发送电子邮件或进一步自定义,我建议您考虑实施“验证后挂钩”,您可以在此处阅读:https://laravel.com/docs/8.x/validation#after-validation-hook
以下是对我有用的方法:
- 在
app/Exceptions/ExistingUserException.php
中创建一个新的验证异常
namespace App\Exceptions;
use Illuminate\Validation\ValidationException;
class ExistingUserException extends ValidationException
{
}
- 在
app/Actions/Fortify/CreateNewUser.php
中将验证分为 2 个步骤,如果表单在其他方面都很好,则抛出扩展 ValidationException
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255'],
'password' => $this->passwordRules(),
'terms' => Jetstream::hasTermsAndPrivacyPolicyFeature() ? ['required', 'accepted'] : '',
])->validate();
$validator = Validator::make($input, [
'email' => ['unique:users'],
], ['email.unique'=>'']);
if ($validator->fails())
{
throw new ExistingUserException($validator);
}
- 在
app/Http/Middleware/CatchExistingUser.php
中创建一个新的中间件
<?php
namespace App\Http\Middleware;
use App\Exceptions\ExistingUserException;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\URL;
class CatchExistingUser
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next, $redirectToRoute = null)
{
$response = $next($request);
if ($response->exception && $response->exception instanceof ExistingUserException)
{
return $request->expectsJson()
? abort(403, 'Your email address is not verified.')
: Redirect::guest(URL::route($redirectToRoute ?: 'verification.notice'));
}
return $response;
}
}
- 通过
config/fortify.php
将中间件注入所有强化路由
'middleware' => [CatchExistingUser::class, 'web'],
- 通过覆盖
routes/web.php
中的路由,从验证页面中删除 auth 中间件
use Illuminate\Http\Request;
use Laravel\Fortify\Contracts\VerifyEmailViewResponse;
...
Route::get('/email/verify', function (Request $request) {
$user = $request->user();
if ($user && $user->hasVerifiedEmail())
{
return redirect()->intended(config('fortify.home'));
}
return app(VerifyEmailViewResponse::class);
})
->name('verification.notice');
自定义异常并不理想,但它似乎比测试存储在 ValidatorException
中的验证器然后在出现多个错误时删除一条消息更干净。我认为这将需要允许验证其他字段同时不泄漏电子邮件的唯一性。
我使用 Jetstream 和 Inertia 创建了一个新站点。目前,该应用程序将 return 显示“电子邮件已被接收”。如果用户尝试使用现有电子邮件注册,则会收到消息。尽管进行了时序分析,但我还是希望将用户帐户的存在保密。有没有办法保持对电子邮件的唯一约束,但如果有人使用现有电子邮件注册,则显示相同的外在行为?理想情况下,我不想创建第二个用户,而是向现有用户发送电子邮件,建议他们重置密码或忽略该电子邮件。
我同意 Unflux 关于不更改此内容的意见,但如果您需要,您可以修改位于 app\Actions\Fortify\CreateNewUser.php
的 CreateNewUser.php
并更改验证消息或修改流程。
负责创建新用户的create()
方法如下所示:
public function create(array $input)
{
//define custom messages
$customValidationMessages = {
'email.unique' => 'New Message',
}
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], //email validation rules here
'password' => $this->passwordRules(),
], $customValidationMessages)->validate(); //add the variable containing the custom message(s) here
return User::create([
'name' => $input['name'],
'email' => $input['email'],
'password' => Hash::make($input['password']),
'api_token' => Str::random(60),
]);
}
如果您需要向用户发送电子邮件或进一步自定义,我建议您考虑实施“验证后挂钩”,您可以在此处阅读:https://laravel.com/docs/8.x/validation#after-validation-hook
以下是对我有用的方法:
- 在
app/Exceptions/ExistingUserException.php
中创建一个新的验证异常
namespace App\Exceptions;
use Illuminate\Validation\ValidationException;
class ExistingUserException extends ValidationException
{
}
- 在
app/Actions/Fortify/CreateNewUser.php
中将验证分为 2 个步骤,如果表单在其他方面都很好,则抛出扩展ValidationException
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255'],
'password' => $this->passwordRules(),
'terms' => Jetstream::hasTermsAndPrivacyPolicyFeature() ? ['required', 'accepted'] : '',
])->validate();
$validator = Validator::make($input, [
'email' => ['unique:users'],
], ['email.unique'=>'']);
if ($validator->fails())
{
throw new ExistingUserException($validator);
}
- 在
app/Http/Middleware/CatchExistingUser.php
中创建一个新的中间件
<?php
namespace App\Http\Middleware;
use App\Exceptions\ExistingUserException;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\URL;
class CatchExistingUser
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next, $redirectToRoute = null)
{
$response = $next($request);
if ($response->exception && $response->exception instanceof ExistingUserException)
{
return $request->expectsJson()
? abort(403, 'Your email address is not verified.')
: Redirect::guest(URL::route($redirectToRoute ?: 'verification.notice'));
}
return $response;
}
}
- 通过
config/fortify.php
将中间件注入所有强化路由
'middleware' => [CatchExistingUser::class, 'web'],
- 通过覆盖
routes/web.php
中的路由,从验证页面中删除 auth 中间件
use Illuminate\Http\Request;
use Laravel\Fortify\Contracts\VerifyEmailViewResponse;
...
Route::get('/email/verify', function (Request $request) {
$user = $request->user();
if ($user && $user->hasVerifiedEmail())
{
return redirect()->intended(config('fortify.home'));
}
return app(VerifyEmailViewResponse::class);
})
->name('verification.notice');
自定义异常并不理想,但它似乎比测试存储在 ValidatorException
中的验证器然后在出现多个错误时删除一条消息更干净。我认为这将需要允许验证其他字段同时不泄漏电子邮件的唯一性。