beskhue/cookietokenauth

记住 CakePHP 用户通过 token 糖果进行认证。

安装次数: 2,306

依赖项: 0

建议者: 0

安全性: 0

星标: 14

关注者: 6

分支: 10

公开问题: 0

类型:cakephp-plugin

2.0.0 2017-11-18 22:57 UTC

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的用户将被登录。为此,在你的AppControllerbeforeFilter中放置类似以下内容。注意,你可能还需要更改你正在执行的当前标识方法。见下一节创建令牌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');
    }

    /* ... */    
}