Laravel 9密码确认中间件功能不起作用

huangapple go评论54阅读模式
英文:

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 是我们可以在路由文件中设置的参数。

$redirectToRoutehandle 方法中像这样使用:

$this->urlGenerator->route($redirectToRoute ?? 'password.confirm')

$passwordTimeoutSecondsshouldConfirmPassword 方法中使用:

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

huangapple
  • 本文由 发表于 2023年2月6日 15:04:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/75358255.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定