简体   繁体   English

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

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

I'm trying to set up some page in Laravel that require a password to view.我正在尝试在 Laravel 中设置一些需要密码才能查看的页面。

A page is a model, called Page.页面是一个模型,称为页面。

Each page has an associated password, stored in the Pages database table.每个页面都有一个关联的密码,存储在页面数据库表中。

The schema架构

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();
});

I have a route, eg Route::get('/page/{url}', 'PageController@index')->middleware('gate');我有一条路线,例如Route::get('/page/{url}', 'PageController@index')->middleware('gate'); which will show the 'page', it's just a blade/vue file with specific information injected into the template.这将显示“页面”,它只是一个刀片/vue 文件,其中包含注入模板的特定信息。 These pages allow the user to upload files via AJAX.这些页面允许用户通过 AJAX 上传文件。

Currently, I created some middleware to actual authentication part.目前,我为实际的身份验证部分创建了一些中间件。

Middleware中间件

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')]);
}

PublicController.php公共控制器.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');
  }

}

The idea of the middleware/auth method was to redirect the user to a login page if they weren't authed.中间件/身份验证方法的想法是将用户重定向到未经过身份验证的登录页面。 This login page consists only of a password that you need to enter.此登录页面仅包含您需要输入的密码。

Once they enter it, I set a cookie so that they can bypass having to re-login again.一旦他们进入,我就设置了一个 cookie,这样他们就可以绕过重新登录的过程。

I now realise that is is insecure, or at least it seems that way as the expiry time of the cookie can be manipulated by the client/user - resulting in them being able to stay logged in forever.我现在意识到这是不安全的,或者至少看起来是这样,因为客户端/用户可以操纵 cookie 的到期时间 - 导致他们能够永远保持登录状态。

Just wish to re-iterate that the method described above is working, but it is insecure.只想重申上述方法有效,但不安全。 I also should re-iterate that these 'pages' allow users to upload files via ajax.我还应该重申,这些“页面”允许用户通过 ajax 上传文件。 And only should the user be allowed to upload if they're on that specific page eg by CSRF.并且只有当用户在特定页面上时才允许上传,例如通过 CSRF。

I need a secure way to password protect pages, which the expiry time of the 'session' can be customised.我需要一种安全的方式来密码保护页面,可以自定义“会话”的到期时间。 I'd also need a way to 'refresh' or 'extend' the active session without a page refresh using AJAX so that the user can stay on the upload page (in case uploads take a long time).我还需要一种在不使用 AJAX 刷新页面的情况下“刷新”或“扩展”活动会话的方法,以便用户可以停留在上传页面上(以防上传需要很长时间)。

Standard user account with username/email & password is not applicable.具有用户名/电子邮件和密码的标准用户帐户不适用。 Password only.只有密码。

Wordpress has this feature built in - why is it so hard to do with Laravel for what seems so trivial? Wordpress 内置了这个功能 - 为什么用 Laravel 做看起来如此微不足道的事情这么难?

How would you approach this?你会如何处理这个问题?

This is how I would have done:这就是我会做的:

Standard user account with username/email & password is not applicable.具有用户名/电子邮件和密码的标准用户帐户不适用。 Password only.只有密码。

For non standard user account, you may yourself generate a guest id on every correct password entered and store it to session.对于非标准用户帐户,您可以自己在输入的每个正确密码上生成一个访客 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();
});

You can just query this way to check authentication您可以通过这种方式查询以检查身份验证

$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
}

Just wish to re-iterate that the method described above is working, but it is insecure.只想重申上述方法有效,但不安全。 I also should re-iterate that these 'pages' allow users to upload files via ajax.我还应该重申,这些“页面”允许用户通过 ajax 上传文件。 And only should the user be allowed to upload if they're on that specific page eg by CSRF.并且只有当用户在特定页面上时才允许上传,例如通过 CSRF。

I need a secure way to password protect pages, which the expiry time of the 'session' can be customised.我需要一种安全的方式来密码保护页面,可以自定义“会话”的到期时间。 I'd also need a way to 'refresh' or 'extend' the active session without a page refresh using AJAX so that the user can stay on the upload page (in case uploads take a long time).我还需要一种在不使用 AJAX 刷新页面的情况下“刷新”或“扩展”活动会话的方法,以便用户可以停留在上传页面上(以防上传需要很长时间)。

From your ajax you can just increment the expiry time on active_guests table.从您的 ajax 中,您可以增加active_guests表上的到期时间。

For longer upload time to be extended you may add a last_activity as timestamp.如需延长上传时间,您可以添加last_activity作为时间戳。

Writing your own authentication solution is hard.编写自己的身份验证解决方案很困难。 Is it possible to reconsider the strategy for securing the pages?是否可以重新考虑保护页面的策略?

If you able to follow the normal user based authentication strategy then you could utilise the authentication services which Laravel provides and it may also provide other advantages by removing edge cases you may encounter.如果您能够遵循基于普通用户的身份验证策略,那么您可以利用 Laravel 提供的身份验证服务,它还可以通过消除您可能遇到的边缘情况来提供其他优势。

Depending on the number of pages you have to authenticate, a boolean column for each page could be added to the User table or you could add a "pages" column of type sting which holds a list of pages this user has access to.根据您必须验证的页面数量,可以将每个页面的布尔列添加到用户表中,或者您可以添加类型为 sting 的“页面”列,其中包含该用户有权访问的页面列表。

The Laravel Authorization Policies ( https://laravel.com/docs/6.x/authorization#creating-policies ) can then be used to enforce access to the page and within Blade you can use the policy to build the dynamic list of pages available to the user ( https://laravel.com/docs/6.x/authorization#via-blade-templates )然后可以使用 Laravel 授权策略 ( https://laravel.com/docs/6.x/authorization#creating-policies ) 来强制访问页面,并且在 Blade 中,您可以使用该策略来构建页面的动态列表可供用户使用( https://laravel.com/docs/6.x/authorization#via-blade-templates

Other benefits: - Avoids sharing a common password for each page.其他好处: - 避免为每个页面共享一个通用密码。 You may not know if the password has been shared outside of the authorised group of users and changing it will impact all users of the page.您可能不知道密码是否已在授权用户组之外共享,更改密码会影响页面的所有用户。

  • If a user forgets a password then they can utilise the standard Password Reset process.如果用户忘记密码,那么他们可以使用标准的密码重置过程。

  • User does not need to track multiple passwords if they have access to multiple pages and Password managers struggle when there are multiple passwords for a domain.如果用户可以访问多个页面,则用户不需要跟踪多个密码,而当一个域有多个密码时,密码管理器会遇到困难。

  • Knowing which pages a user has access to can assist usability by providing a homepage that lists all the pages available to the specific user.通过提供列出特定用户可用的所有页面的主页,了解用户可以访问哪些页面可以帮助提高可用性。

Use session instead of cookies.使用会话而不是 cookie。 Changes for Middleware :中间件的变化:

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');
}

Changes for Controller :控制器的变化:

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');
    }
}

You can use hashed password to save in the database using MD5 or SHA256 or SHA512 algorithm.您可以使用 MD5 或 SHA256 或 SHA512 算法将哈希密码保存在数据库中。 For more about session , study the Laravel session documentation click here有关 session 的更多信息,请研究 Laravel session 文档,请单击此处

You can configure session.php , location: root folder/config/session.php .您可以配置session.php ,位置:根文件夹/config/session.php Such as when user close the browser then destroyed the session.例如当用户关闭浏览器然后破坏会话时。

'expire_on_close' => true 

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

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