繁体   English   中英

如何使用 Laravel 密码保护页面?

[英]How to password protect a page with Laravel?

我正在尝试在 Laravel 中设置一些需要密码才能查看的页面。

页面是一个模型,称为页面。

每个页面都有一个关联的密码,存储在页面数据库表中。

架构

Schema::create('pages', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->string('name');
    $table->string('client_id');
    $table->string('url');
    $table->text('content');
    $table->string('password');
    $table->timestamps();
});

我有一条路线,例如Route::get('/page/{url}', 'PageController@index')->middleware('gate'); 这将显示“页面”,它只是一个刀片/vue 文件,其中包含注入模板的特定信息。 这些页面允许用户通过 AJAX 上传文件。

目前,我为实际的身份验证部分创建了一些中间件。

中间件

public function handle($request, Closure $next)
{
    if(Cookie::get($request->route('url'))){
        return $next($request);
    }
    session(['page' => $request->route('url')]);
    return redirect()->route('gate',['page'=> $request->route('url')]);
}

公共控制器.php

public function gate_check(Request $request)
{
  //this part just ensures the correct page is loaded after being authed
  $past = parse_url($request->session()->get('_previous')['url']);

  if(array_key_exists('query', $past)){
    $page = str_replace('page=', '',parse_url($request->session()->get('_previous')['url'])['query']);

    $stored_password = Page::where('url', $page)->first()->password;
    $password = $request->password;  

    if($password === $stored_password){
      //if password matches, then redirect to that page
      return redirect()->route('page', session('page'));
    } else {
      //else redirect them back to the login page to try again
      return back();
    }
  } else {
    //if there is no page information that use should go to, just send them to google instead
    return redirect('https://google.com');
  }

}

中间件/身份验证方法的想法是将用户重定向到未经过身份验证的登录页面。 此登录页面仅包含您需要输入的密码。

一旦他们进入,我就设置了一个 cookie,这样他们就可以绕过重新登录的过程。

我现在意识到这是不安全的,或者至少看起来是这样,因为客户端/用户可以操纵 cookie 的到期时间 - 导致他们能够永远保持登录状态。

只想重申上述方法有效,但不安全。 我还应该重申,这些“页面”允许用户通过 ajax 上传文件。 并且只有当用户在特定页面上时才允许上传,例如通过 CSRF。

我需要一种安全的方式来密码保护页面,可以自定义“会话”的到期时间。 我还需要一种在不使用 AJAX 刷新页面的情况下“刷新”或“扩展”活动会话的方法,以便用户可以停留在上传页面上(以防上传需要很长时间)。

具有用户名/电子邮件和密码的标准用户帐户不适用。 只有密码。

Wordpress 内置了这个功能 - 为什么用 Laravel 做看起来如此微不足道的事情这么难?

你会如何处理这个问题?

这就是我会做的:

具有用户名/电子邮件和密码的标准用户帐户不适用。 只有密码。

对于非标准用户帐户,您可以自己在输入的每个正确密码上生成一个访客 ID,并将其存储到会话中。

Schema::create('active_guests', function (Blueprint $table) {
$table->bigIncrements('guest_id'); # on your model specify this as primary key
$table->unsignedBigInteger('page_id'); # authorized for after validating password
$table->integer('expires_at'); # store it as unixtimestamp now()->addHours(5)->timestamp
$table->timestamps();
});

您可以通过这种方式查询以检查身份验证

$page = Page::where('url', $page)->where('password', $password)->first();
if ($page) {
ActiveGuest::updateOrcreate(....);
Session::get('pages_authorized_for', [array_of_pages]);
// push the new page id and store it back to session as array
} else {
// incorrect password or page removed
}

只想重申上述方法有效,但不安全。 我还应该重申,这些“页面”允许用户通过 ajax 上传文件。 并且只有当用户在特定页面上时才允许上传,例如通过 CSRF。

我需要一种安全的方式来密码保护页面,可以自定义“会话”的到期时间。 我还需要一种在不使用 AJAX 刷新页面的情况下“刷新”或“扩展”活动会话的方法,以便用户可以停留在上传页面上(以防上传需要很长时间)。

从您的 ajax 中,您可以增加active_guests表上的到期时间。

如需延长上传时间,您可以添加last_activity作为时间戳。

编写自己的身份验证解决方案很困难。 是否可以重新考虑保护页面的策略?

如果您能够遵循基于普通用户的身份验证策略,那么您可以利用 Laravel 提供的身份验证服务,它还可以通过消除您可能遇到的边缘情况来提供其他优势。

根据您必须验证的页面数量,可以将每个页面的布尔列添加到用户表中,或者您可以添加类型为 sting 的“页面”列,其中包含该用户有权访问的页面列表。

然后可以使用 Laravel 授权策略 ( https://laravel.com/docs/6.x/authorization#creating-policies ) 来强制访问页面,并且在 Blade 中,您可以使用该策略来构建页面的动态列表可供用户使用( https://laravel.com/docs/6.x/authorization#via-blade-templates

其他好处: - 避免为每个页面共享一个通用密码。 您可能不知道密码是否已在授权用户组之外共享,更改密码会影响页面的所有用户。

  • 如果用户忘记密码,那么他们可以使用标准的密码重置过程。

  • 如果用户可以访问多个页面,则用户不需要跟踪多个密码,而当一个域有多个密码时,密码管理器会遇到困难。

  • 通过提供列出特定用户可用的所有页面的主页,了解用户可以访问哪些页面可以帮助提高可用性。

使用会话而不是 cookie。 中间件的变化:

public function handle($request, Closure $next)
{   

    if(in_array($request->route('url'), session('pages',[]))){
       return $next($request);
    }

    session(["current-page"=>$request->route('url')]);
    return redirect()->route('gate');
}

控制器的变化:

public function gate_check(Request $request)
{
    if(session()->has("current-page")){

        $stored_password = Page::where('url', session("current-page"))
           ->first()->password;

        if($request->password === $stored_password){
            $pages = session("pages",[]);
            array_push($pages, session("current-page"));
            session(["pages"=> $pages]);
            //if password matches, then redirect to that page
            return redirect()->route('page', ["url" => session("current-page")]);
        } else {
            //else redirect them back to the login page to try again
            return back();
        }
    } else {
        //if there is no page information that use should go to, just send them 
        // to google instead
        return redirect('https://google.com');
    }
}

您可以使用 MD5 或 SHA256 或 SHA512 算法将哈希密码保存在数据库中。 有关 session 的更多信息,请研究 Laravel session 文档,请单击此处

您可以配置session.php ,位置:根文件夹/config/session.php 例如当用户关闭浏览器然后破坏会话时。

'expire_on_close' => true 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM