英文:
Laravel 9 password.confirm middleware feature not working
问题
我正在尝试在我的一些需要安全保护的路由中使用password.confirm
中间件。我希望用户在生成特定的POST请求时应该确认他的密码。
此外,password.confirm
中间件已添加到app/Http/Kernel.php
文件的$routeMiddleware
属性中。
这是我的web.php
中路由的样子。
Route::post('fetchResult', [ReportController::class, 'fetchResult'])->name('fetchComplaintResult')->middleware('password.confirm');
但它不起作用。当我生成POST请求时,它直接命中到控制器的fetchResult
方法,与往常一样。
我的控制器函数:
public function fetchResult(Request $request)
{
Model::create([
'id' => $request->id,
'action' => $request->action,
'comments' => $request->comment
]);
// 其他操作
}
我是否遗漏了什么?
英文:
I am trying to use the password.confirm middleware in some of my routes which I need to be secured. I want a user should confirm his password when he generate a specific post request.
Also, password.confirm middleware is added $routeMiddleware property in the app/Http/Kernel.php file.
This is what my route looks like in web.php.
Route::post('fetchResult', [ReportController::class, 'fetchResult'])->name('fetchComplaintResult')->middleware('password.confirm');
But it is not working. When I generate post request it directly hit to controller fetchResult method as usual.
My controller function:
public function fetchResult(Request $request)
{
Model::create([
'id' => $request->id,
'action' => $request->action,
'comments' => $request->comment
]);
// Other Action
}
Am I missing something ??
答案1
得分: 2
如果你想在每次需要确认密码时得到提示,你应该像这样编写你的路由:
Route::post('fetchResult', [ReportController::class, 'fetchResult'])
->name('fetchComplaintResult')
->middleware('password.confirm:password.confirm,1');
为什么?
password.confirm
中间件映射到 Illuminate\Auth\Middleware\RequirePassword
类。以下是它的代码。
use Closure;
use Illuminate\Contracts\Routing\ResponseFactory;
use Illuminate\Contracts\Routing\UrlGenerator;
class RequirePassword
{
/**
* The response factory instance.
*
* @var \Illuminate\Contracts\Routing\ResponseFactory
*/
protected $responseFactory;
/**
* The URL generator instance.
*
* @var \Illuminate\Contracts\Routing\UrlGenerator
*/
protected $urlGenerator;
/**
* The password timeout.
*
* @var int
*/
protected $passwordTimeout;
/**
* 创建一个新的中间件实例。
*
* @param \Illuminate\Contracts\Routing\ResponseFactory $responseFactory
* @param \Illuminate\Contracts\Routing\UrlGenerator $urlGenerator
* @param int|null $passwordTimeout
* @return void
*/
public function __construct(ResponseFactory $responseFactory, UrlGenerator $urlGenerator, $passwordTimeout = null)
{
$this->responseFactory = $responseFactory;
$this->urlGenerator = $urlGenerator;
$this->passwordTimeout = $passwordTimeout ?: 10800;
}
/**
* 处理传入的请求。
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $redirectToRoute
* @param int|null $passwordTimeoutSeconds
* @return mixed
*/
public function handle($request, Closure $next, $redirectToRoute = null, $passwordTimeoutSeconds = null)
{
if ($this->shouldConfirmPassword($request, $passwordTimeoutSeconds)) {
if ($request->expectsJson()) {
return $this->responseFactory->json([
'message' => 'Password confirmation required.',
], 423);
}
return $this->responseFactory->redirectGuest(
$this->urlGenerator->route($redirectToRoute ?? 'password.confirm')
);
}
return $next($request);
}
/**
* 确定确认超时是否已过期。
*
* @param \Illuminate\Http\Request $request
* @param int|null $passwordTimeoutSeconds
* @return bool
*/
protected function shouldConfirmPassword($request, $passwordTimeoutSeconds = null)
{
$confirmedAt = time() - $request->session()->get('auth.password_confirmed_at', 0);
return $confirmedAt > ($passwordTimeoutSeconds ?? $this->passwordTimeout);
}
}
需要注意的重要部分是 handle
方法的签名:
public function handle($request, Closure $next, $redirectToRoute = null, $passwordTimeoutSeconds = null)
在这里,$redirectToRoute
和 $passwordTimeoutSeconds
是我们可以在路由文件中设置的参数。
$redirectToRoute
在 handle
方法中像这样使用:
$this->urlGenerator->route($redirectToRoute ?? 'password.confirm')
$passwordTimeoutSeconds
在 shouldConfirmPassword
方法中使用:
return $confirmedAt > ($passwordTimeoutSeconds ?? $this->passwordTimeout);
由于它被设置为 null
,所以与之比较的值是 $this->passwordTimeout
,它在构造函数中被设置为 10800(10800 秒 = 180 分钟 = 3 小时)。
因此,总结一下,我们需要设置 $passwordTimeoutSeconds
参数。由于它是第二个参数,我们还需要设置 $redirectToRoute
参数。
更多信息,请参考 Laravel 文档。
英文:
If you want to get prompted to confirm your password every time you should write your route like this:
Route::post('fetchResult', [ReportController::class, 'fetchResult'])
->name('fetchComplaintResult')
->middleware('password.confirm:password.confirm,1');
Why?
The password.confirm
middleware maps to the Illuminate\Auth\Middleware\RequirePassword
class. This is its code.
use Closure;
use Illuminate\Contracts\Routing\ResponseFactory;
use Illuminate\Contracts\Routing\UrlGenerator;
class RequirePassword
{
/**
* The response factory instance.
*
* @var \Illuminate\Contracts\Routing\ResponseFactory
*/
protected $responseFactory;
/**
* The URL generator instance.
*
* @var \Illuminate\Contracts\Routing\UrlGenerator
*/
protected $urlGenerator;
/**
* The password timeout.
*
* @var int
*/
protected $passwordTimeout;
/**
* Create a new middleware instance.
*
* @param \Illuminate\Contracts\Routing\ResponseFactory $responseFactory
* @param \Illuminate\Contracts\Routing\UrlGenerator $urlGenerator
* @param int|null $passwordTimeout
* @return void
*/
public function __construct(ResponseFactory $responseFactory, UrlGenerator $urlGenerator, $passwordTimeout = null)
{
$this->responseFactory = $responseFactory;
$this->urlGenerator = $urlGenerator;
$this->passwordTimeout = $passwordTimeout ?: 10800;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $redirectToRoute
* @param int|null $passwordTimeoutSeconds
* @return mixed
*/
public function handle($request, Closure $next, $redirectToRoute = null, $passwordTimeoutSeconds = null)
{
if ($this->shouldConfirmPassword($request, $passwordTimeoutSeconds)) {
if ($request->expectsJson()) {
return $this->responseFactory->json([
'message' => 'Password confirmation required.',
], 423);
}
return $this->responseFactory->redirectGuest(
$this->urlGenerator->route($redirectToRoute ?? 'password.confirm')
);
}
return $next($request);
}
/**
* Determine if the confirmation timeout has expired.
*
* @param \Illuminate\Http\Request $request
* @param int|null $passwordTimeoutSeconds
* @return bool
*/
protected function shouldConfirmPassword($request, $passwordTimeoutSeconds = null)
{
$confirmedAt = time() - $request->session()->get('auth.password_confirmed_at', 0);
return $confirmedAt > ($passwordTimeoutSeconds ?? $this->passwordTimeout);
}
}
The important parts to note are the handle
method's signature:
public function handle($request, Closure $next, $redirectToRoute = null, $passwordTimeoutSeconds = null)
Here, $redirectToRoute
and $passwordTimeoutSeconds
are arguments we can set in the route file.
$redirectToRoute
is used like this in the handle
method:
$this->urlGenerator->route($redirectToRoute ?? 'password.confirm')
$passwordTimeoutSeconds
is used here in the shouldConfirmPassword
method.
return $confirmedAt > ($passwordTimeoutSeconds ?? $this->passwordTimeout);
Since it's set to null
, the value $confirmedAt
is compared to is $this->passwordTimeout
, which is set in the constructor to 10800. (10800 seconds = 180 minutes = 3 hours).
So in summary we need to set the $passwordTimeoutSeconds
parameter. Since it's the second parameter, we also need to set the $redirectToRoute
parameter.
https://laravel.com/docs/9.x/middleware#middleware-parameters
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论