承接 rrd108/api-token-authenticator 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

rrd108/api-token-authenticator

Composer 安装命令:

composer require rrd108/api-token-authenticator

包简介

A Simple Token Authentication Plugin for CakePHP 5 REST API-s

README 文档

README

A Simple Token Authentication Plugin for CakePHP 5 REST API-s.

For CakePHP 4 version see rrd108/api-token-authenticator

For a REST API you may want to use a cors plugin like rrd108/cakephp-cors and a json api exception plugin like rrd108/cakephp-json-api-exception.

If you use vuejs as your frontend you may wnat to bake your vue components with rrd108/vue-bake.

Configuration

Users table

In your users table you should have a field named token, or whatever name you choose for the token. We will use token in the examples. The token value will not be automatically generated by the plugin. You can generate it in your UsersController.php file's login() method (or elsewhere if you want). See the example below.

Changing the default settings

If you are happy with the default settings, you can skip this section.

For defaults see config/apiTokenAuthenticator.php file in the plugin's directory.

If you want to change any of the values then create your own config/apiTokenAuthenticator.php file at your project's config directory. In your config file, you should use only those keys that you want to change. It will be merged to the default one. So, for example, if you are happy with all the options, except in your case the token's header name is Authorization, then you have to put this into your on config file.

<?php
return [
  'ApiTokenAuthenticator' => [
    'header' => 'Authorization',
  ]
];

Authorization with Bearer token

If you want to use the Authorization header with Bearer token, you should set the header key to Authorization and the prefix key to Bearer in your config/apiTokenAuthenticator.php file.

<?php
return [
  'ApiTokenAuthenticator' => [
    'header' => 'Authorization',
    'prefix' => 'Bearer',
  ]
];

Authentication

The plugin authentication workflow is the following.

At your client appliacation you should send a POST request to /users/login.json (or what you set in your config/apiTokenAuthenticator.php file) with a JSON object like this.

{
    "email": "rrd@webmania.cc",
    "password": "rrd"
}

If the login was successful than you will get a response like this.

{
    "user": {
        "id": 1,
        "token": "yourSecretTokenComingFromTheDatabase"
    }
}

Than you can use this token to authenticate yourself for accessing urls what requires authentication. The token should be sent in a request header named Token (or what you set in your config/apiTokenAuthenticator.php file).

Installation

1. Install the plugin

Including the plugin is pretty much as with every other CakePHP plugin:

composer require rrd108/api-token-authenticator

Then, to load the plugin either run the following command:

bin/cake plugin load ApiTokenAuthenticator

or manually add the following line to your app's config/plugins.php:

return [
  // other plugins
  'ApiTokenAuthenticator' => [],
];

2. Disable CSRF protection

You should comment out (or delete) CsrfProtectionMiddleware in your /src/Application.php file's middleware() method.

3. Load the plugin's components

At your AppController.php file's initialize() function you should include these components:

public function initialize(): void
{
  parent::initialize();
  $this->loadComponent('Authentication.Authentication');
}

And add JSON view support to AppController.php.

use Cake\View\JsonView;

public function viewClasses(): array
{
  return [JsonView::class];
}

4. Set password hasher

Update your src/Model/Entity/User.php file adding the following.

use Authentication\PasswordHasher\DefaultPasswordHasher;
protected function _setPassword(string $password)
{
  $hasher = new DefaultPasswordHasher();
  return $hasher->hash($password);
}

Do not forget to remove the token field from the $_hidden array.

5. Set extensions for routes

As you probably will use JSON urls, do not forget to add this line to your config/routes.php file.

$routes->scope('/', function (RouteBuilder $builder): void {
  // other routes
  $builder->setExtensions(['json']);
  $builder->resources('Users');

  $builder->fallbacks();
});

5. Set JSON response in controllers

In your controllers you should set the JSON response type.

// for example in UsersController.php
public function index()
{
  $query = $this->Users->find();
  $users = $this->paginate($query);

  $this->set(compact('users'));
  $this->viewBuilder()->setOption('serialize', ['users']);
}

As CakePHP response use content type negotiation it is important to add the Accept: application/json header to your requests.

That's it. It should be up and running.

The login() method

If you use static tokens

Login method is not added automatically, you should implement it. Here is an example how.

public function login()
{
  $result = $this->Authentication->getResult();
  if ($result->isValid()) {
    $user = $this->Authentication->getIdentity()->getOriginalData();
    $this->set(compact('user'));
    $this->viewBuilder()->setOption('serialize', ['user']);
  }
}

The login method should be added to the list of actions that are allowed to be accessed without authentication.

public function beforeFilter(\Cake\Event\EventInterface $event)
{
  parent::beforeFilter($event);
  $this->Authentication->allowUnauthenticated(['login']);
}

If you use dynamic tokens

public function login()
{
  $result = $this->Authentication->getResult();
  if ($result->isValid()) {
    $user = $this->Authentication->getIdentity()->getOriginalData();
    $user->token = $this->generateToken();
    $user = $this->Users->save($user);
    $user = $this->Users->get($user->id);

    $this->set(compact('user'));
    $this->viewBuilder()->setOption('serialize', ['user']);
  }
  // if login failed you can throw an exception, suggested: rrd108/cakephp-json-api-exception
}

private function generateToken(int $length = 36)
{
  $random = base64_encode(Security::randomBytes($length));
  $cleaned = preg_replace('/[^A-Za-z0-9]/', '', $random);
  return substr($cleaned, 0, $length);
}

Token expiration

By default tokens are not invalidated by the plugin, you can use them permanently or as long as there is no new login session like in the example code above.

If you want the plugin to use tokens only for a certain period of time, you should do the following steps.

  1. Add a column to your users table named token_expiration and set it's type to datetime. You can use a different field name, but you have to change it in the following steps.

  2. In your config/apiTokenAuthenticator.php file set 'tokenExpiration' => 'token_expiration'.

  3. Update your src/Model/Entity/User.php file adding the field to the $accessible array.

protected $_accessible = [
  'email' => true,
  // your other fields here
  'token' => true,
  'token_expiration' => true,
];
  1. Update your src/Model/Table/UsersTable.php file adding the following.
$validator
  ->dateTime('token_expiration')
  ->allowEmptyDateTime('token_expiration');
  1. In your src/Controller/UsersController.php file you should modify login() method.
public function login()
{
  $result = $this->Authentication->getResult();
  if ($result->isValid()) {
    $user = $this->Authentication->getIdentity()->getOriginalData();
    list($user->token, $user->token_expiration) = $this->generateToken();
    $user = $this->Users->save($user);

    $this->set(compact('user'));
    $this->viewBuilder()->setOption('serialize', ['user']);

    // delete all expired tokens
    $this->Users->updateAll(
      ['token' => null, 'token_expiration' => null],
      ['token_expiration <' => Chronos::now()]
    );
  }
}

private function generateToken(int $length = 36, string $expiration = '+6 hours')
{
  $random = base64_encode(Security::randomBytes($length));
  $cleaned = preg_replace('/[^A-Za-z0-9]/', '', $random);
  return [$cleaned, strtotime($expiration)];
}

Access without authentication

If you want to let the users to access a resource without authentication you should state it in the controller's beforeFilter() method. The login, register methods are good candidates to allow unauthenticated access.

// in UsersController.php
public function beforeFilter(\Cake\Event\EventInterface $event)
{
  parent::beforeFilter($event);
  $this->Authentication->allowUnauthenticated(['login', 'index']);
}

This will allow users to access /users/login.json and /users.json url without authentication.

rrd108/api-token-authenticator 适用场景与选型建议

rrd108/api-token-authenticator 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 2.02k 次下载、GitHub Stars 达 3, 最近一次更新时间为 2021 年 07 月 09 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 rrd108/api-token-authenticator 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 rrd108/api-token-authenticator 我们能提供哪些服务?
定制开发 / 二次开发

基于 rrd108/api-token-authenticator 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 2.02k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 4
  • 点击次数: 18
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 3
  • Watchers: 1
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2021-07-09