beskhue / cookietokenauth
记住 CakePHP 用户通过 token 糖果进行认证。
Requires
- php: >=5.6
- cakephp/cakephp: ~3.4
- cakephp/migrations: @stable
This package is not auto-updated.
Last update: 2024-09-14 18:53:05 UTC
README
这是一个 CakePHP 插件,允许用户使用 cookies 进行长期登录会话。会话通过两个变量进行标识:一个随机序列变量和一个令牌。会话存储在数据库中,并与属于它们用户关联。令牌变量以哈希形式存储。
为什么使用 CookieTokenAuth?
CookieTokenAuth 比在 cookie 中存储用户名和(哈希过的)密码更安全。
cookie 中没有密码(也没有密码哈希)
如果会话 cookie 泄露,用户的密码哈希就会可用。也没有方法来使会话无效。
对会话的控制
此方法比在 cookie 中存储用户名和令牌更安全。首先,我们现在为不同的浏览器有独立的会话。当用户在某个浏览器中注销时,该会话可以从数据库中删除。其次,当尝试会话盗窃时,我们理想情况下会使用户的会话无效。如果没有系列变量,这意味着仅通过提供具有用户名的 cookies 就可以针对特定用户执行拒绝服务攻击。在这里,攻击者首先必须猜测(随机)序列变量。
令牌安全存储
有效的令牌几乎与有效的密码一样安全,因此它应该被当作一样对待。通过仅在数据库中存储令牌哈希,攻击者无法在会话数据库泄露时访问用户帐户。
最小化 cookie 泄露
为了增加安全性,令牌 cookie 仅在特殊认证页面上发送到服务器。该页面在每次会话中仅由客户端访问一次。因此,窃取 cookie 的机会最小化。此行为可以被禁用,例如,以改善会话的第一次访问的网站加载时间。
由 CakePHP 加密
在所有这些安全措施之上,令牌 cookie 自然由 CakePHP 加密。
安装
将以下内容放在你的 composer.json
中
"require": {
"beskhue/cookietokenauth": "2.0.0"
}
然后运行
php composer.phar update
数据库
使用 CakePHP 的官方迁移插件 设置插件数据库。
cake migrations migrate -p Beskhue/CookieTokenAuth
如果你有特定的需求,例如不同的用户模型、不同的表名、不同的主键数据类型(如果迁移失败,请注意有符号和无符号整数),或者完全不同的主键,你必须更改位于 config/Migrations/20170510221552_CreateAuthTokens.php
的迁移文件。
使用方法
引导
将以下内容放在你的 config/bootstrap.php
文件中
Plugin::load('Beskhue/CookieTokenAuth', ['routes' => true]);
或者使用 bake
"bin/cake" plugin load --routes Beskhue/CookieTokenAuth
设置 AuthComponent
更新你的 AuthComponent 配置以使用 CookieTokenAuth。例如,如果你还使用表单认证来登录用户,你可以写
$this->loadComponent('Auth', [ 'authenticate' => [ 'Beskhue/CookieTokenAuth.CookieToken', 'Form' ] ]);
如果用户模型或用户字段名称与默认值不同,你可以配置插件
$this->loadComponent('Auth', [ 'authenticate' => [ 'Beskhue/CookieTokenAuth.CookieToken' => [ 'fields' => ['username' => 'email', 'password' => 'passwd'], 'userModel' => 'Members' ], 'Form' => [ 'fields' => ['username' => 'email', 'password' => 'passwd'], 'userModel' => 'Members' ], ] ]);
配置
完整的默认配置如下
'fields' => [ 'username' => 'username', 'password' => 'password', ], 'userModel' => 'Users', 'hash' => 'sha256', 'cookie' => [ 'name' => 'userdata', 'expires' => '+10 weeks', 'encryption' => 'aes', 'httpOnly' => true ], 'minimizeCookieExposure' => true, 'minimizeCookieExposureRedirectCallback' => function(\Cake\Http\ServerRequest $request, \Cake\Http\Response $response) { return true; }, 'setCookieAfterIdentify' => true, 'tokenError' => __('A session token mismatch was detected. You have been logged out.')
请注意,hash
仅用于生成令牌--数据库中存储的令牌使用 DefaultPasswordHasher 哈希。其值可以是任何 PHP 哈希算法。
如果将minimizeCookieExposure
设置为false
,则客户端在会话开始时不会两次被重定向以尝试使用令牌cookie进行登录。相反,客户端的浏览器现在将在每次请求时发送令牌cookie。这安全性较低。
验证cookie
接下来,你可能希望验证所有控制器中未登录用户的用户身份验证(注意:会话中只尝试一次身份验证)。这确保了具有有效令牌cookie的用户将被登录。为此,在你的AppController
的beforeFilter
中放置类似以下内容。注意,你可能还需要更改你正在执行的当前标识方法。见下一节创建令牌cookie。
if(!$this->Auth->user()) { $user = $this->Auth->identify(); if ($user) { $this->Auth->setUser($user); return $this->redirect($this->Auth->redirectUrl()); } }
创建令牌cookie
在大多数情况下,CookieTokenAuth会自动为你生成令牌cookie。无需进一步配置和集成。
当用户以传统方式(表单、Ldap等)登录时,我们需要创建一个令牌cookie,以便CookieTokenAuth在用户返回时能识别该用户。CookieTokenAuth自动处理非持久性和非无状态的认证适配器执行的标识。这意味着在CakePHP的内置认证适配器中,只有FormAuthenticate
会自动生成令牌cookie。这是因为持久性或无状态的标识方法会在每个请求中标识用户,并导致在每个请求上创建新的cookie令牌。
处理无状态和持久认证
如果你想同时处理持久或无状态的认证标识,可以这样做。这将创建一个令牌,将其添加到数据库中,并且用户的客户端将接收到一个包含令牌的cookie。你可能想要确保用户在每个会话中只被标识一次。
public function identify() { $user = $this->Auth->user(); if ($user) { $cookieTokenComponent = $this->Auth->getAuthenticate('Beskhue/CookieTokenAuth.CookieToken')->getCookieTokenComponent(); $cookieTokenComponent->setCookie($user['id']); } }
禁用自动生成令牌cookie
你可能只想在特定情况下创建令牌cookie,例如当用户勾选了“记住我”复选框时。为此,首先将setCookieAfterIdentify
选项设置为false
(见配置部分)。现在你需要手动创建令牌cookie。
为此,可以在登录操作中添加类似以下内容
public function login() { // ... $user = $this->Auth->user(); if($user) { $this->Auth->setUser($user); if($this->request->getData('remember_me')) { $cookieTokenComponent = $this->Auth->getAuthenticate('Beskhue/CookieTokenAuth.CookieToken')->getCookieTokenComponent(); $cookieTokenComponent->setCookie($user['id']); } } }
并将以下内容添加到登录模板中
<?= $this->Form->checkbox('remember_me', ['id' => 'remember-me']); ?> <?= $this->Form->label('remember_me', __('Remember me')); ?>
在启用最小化cookie暴露时禁用认证重定向
你可能想要禁用特定请求用于最小化cookie暴露的重定向。这可以通过配置一个回调来实现。
该回调接受一个Cake\Http\ServerRequest
和一个Cake\Http\Response
作为参数,并应返回一个布尔值,表示是否执行重定向。当需要重定向以尝试认证用户时,将调用它。如果回调返回true,则执行重定向。如果回调返回false,则不会执行此请求的重定向,并且将在下一个请求中再次调用。
要配置此,在配置期间传递一个可调用的对象给minimizeCookieExposureRedirectCallback
$this->loadComponent('Auth', [ 'authenticate' => [ 'Beskhue/CookieTokenAuth.CookieToken' => [ 'minimizeCookieExposure' => true, 'minimizeCookieExposureRedirectCallback' => function (\Cake\Http\ServerRequest $request, \Cake\Http\Response $response) { return !$request->is('ajax'); } ] ] ]);
或者,你可以提供一个命名函数,例如在AppController
中
class AppController extends Controller { public function initialize() { /* ... */ $this->loadComponent('Auth', [ 'authenticate' => [ 'Beskhue/CookieTokenAuth.CookieToken' => [ 'minimizeCookieExposure' => true, 'minimizeCookieExposureRedirectCallback' => array($this, 'minimizeCookieExposureRedirect') ] ] ]); } public function minimizeCookieExposureRedirect (\Cake\Http\ServerRequest $request, \Cake\Http\Response $response) { return !$request->is('ajax'); } /* ... */ }