sebk/small-swoft-auth

基于 small-orm 的 Swoft jwt 身份验证

1.1.2 2021-10-29 22:21 UTC

This package is auto-updated.

Last update: 2024-09-29 06:03:09 UTC


README

基于 small-orm 的 Swoft jwt 身份验证

包含一个控制器基类,以简化在控制器中实现令牌支持,并与投票者关联来管理用户权限

安装

创建您的 Swoft 项目:http://swoft.io/docs/2.x/en/quick-start/install.html

安装依赖项

composer require sebk/small-orm-core
composer require sebk/small-orm-forms
composer require sebk/swoft-voter

需要 Swoft Voter 包(https://github.com/sebk69/small-swoft-auth

composer require sebk/small-swoft-auth

文档

参数

在 base.php 中,注册 AuthManagerService

return [
...
    \Swoft\Auth\Contract\AuthManagerInterface::class => [
        'class' => \Sebk\SmallSwoftAuth\Service\AuthManagerService::class
    ],
...
];

在 app.php 中,根据您的应用程序注册 app.user,以便 AuthManager 请求您的应用程序用户

return [
...
    'user' => [
        'dao' => ['GenericBundle', 'User'],
        'accountField' => 'login',
        'identityField' => 'id',
    ],
...
];

实现 UserModelInterface

您的应用程序用户模型必须实现 UserModelInterface。 (在此示例中,为了简单起见,密码通过 md5 哈希存储。出于安全原因,请勿使用 md5 哈希,而应首选 SHA-256 哈希或更高版本)

use Sebk\SmallSwoftAuth\Interfaces\UserModelInterface;

class User extends Model implements UserModelInterface
{

    /**
     * Check user password
     * @param string $password
     * @return bool
     */
    public function checkPassword(string $password)
    {
        return $this->getPassword() == md5($password);
    }

}

实现您的投票者

有关配置和实现的详细信息,请参阅 https://github.com/sebk69/small-voter

实现登录

实现您的控制器

为了保护您的控制器

  • 使用 swoft/auth 的 AuthMiddleware
  • 您的控制器必须扩展 TokenSecuredController 抽象类

此外,您可以通过在控制器对象上使用 denyAccessUnlessGranted 方法并使用投票者来通过应用程序的特定规则保护路由

$this->denyAccessUnlessGranted(VoterInterface::ATTRIBUTE_READ, $this);

以下是一个控制器示例

<?php declare(strict_types=1);

namespace App\Http\Controller;

use Sebk\SmallOrmSwoft\Traits\Injection\DaoFactory;
use Sebk\SmallSwoftAuth\Controller\TokenSecuredController;
use Sebk\SwoftVoter\VoterManager\VoterInterface;

use App\Model\OrderBundle\Dao\Customer;

use Swoft\Http\Message\Response;
use Swoft\Http\Server\Annotation\Mapping\Controller;
use Swoft\Http\Server\Annotation\Mapping\RequestMapping;
use Swoft\Http\Server\Annotation\Mapping\RequestMethod;
use Swoft\Http\Server\Annotation\Mapping\Middleware;
use Swoft\Http\Server\Annotation\Mapping\Middlewares;

use Swoft\Http\Message\Request;

use Swoft\Auth\Middleware\AuthMiddleware;


/**
 * Class CustomerController
 *
 * @since 2.0
 *
 * @Controller("api/customers")
 *
 * @Middlewares ({AuthMiddleware::class})
 * @Middleware (AuthMiddleware::class)
 */
class CustomerController extends TokenSecuredController
{
    use DaoFactory;

    /**
     * @RequestMapping("page/{page}/pageSize/{pageSize}", method={RequestMethod::GET})
     * @param int $page
     * @param int $pageSize
     * @param Request $request
     * @return Response
     * @throws \Sebk\SmallOrmCore\QueryBuilder\BracketException
     * @throws \Sebk\SmallOrmCore\QueryBuilder\QueryBuilderException
     */
    public function getCustomerList(int $page, int $pageSize, Request $request)
    {
        // Check user rigths
        $this->denyAccessUnlessGranted(VoterInterface::ATTRIBUTE_READ, $this);

        /** @var Customer $daoCustomer */
        $daoCustomer = $this->daoFactory->get("CommandeBundle", "Customer");
        $customers = $daoCustomer->list($request->getQueryParams(), $page, $pageSize);

        return JsonResponse($customers);
    }

}

用法:登录请求

以下是一个实现登录操作的 AuthController

<?php

namespace App\Http\Controller;

use Sebk\SmallSwoftAuth\Traits\Injection\AuthManagerService;

use Swoft\Auth\Exception\AuthException;
use Swoft\Http\Message\ContentType;
use Swoft\Http\Message\Request;
use Swoft\Http\Message\Response;
use Swoft\Http\Server\Annotation\Mapping\Controller;
use Swoft\Http\Server\Annotation\Mapping\RequestMapping;
use Swoft\Http\Server\Annotation\Mapping\RequestMethod;

use Swoole\Http\Status;

/**
 *
 * @since 2.0
 *
 * @Controller ("api")
 */
class AuthController
{
    use AuthManagerService;

    const LOGIN_FAILED_MESSAGE = 'Login failed !';

    /**
     * @RequestMapping (route="login_check", method={RequestMethod::POST})
     * @param Request $request
     * @return Response
     */
    public function login(Request $request): Response {
        // Check request format
        if (!in_array(ContentType::JSON, $request->getHeader(ContentType::KEY))) {
            return JsonResponse(static::LOGIN_FAILED_MESSAGE)
                ->withStatus(Status::BAD_REQUEST)
            ;
        }

        // Login & sign token
        try {
            $session = $this->authManager->auth($request->getParsedBody());
        } catch (AuthException $e) {
            return JsonResponse(static::LOGIN_FAILED_MESSAGE)
                ->withStatus(Status::UNAUTHORIZED)
            ;
        }

        $tokenData = [
            'token' => $session->getToken(),
            'expired_at' => $session->getExpirationTime()
        ];

        return JsonResponse($tokenData);
    }

}

要测试它,请使用您喜欢的 rest 应用程序在

POST https:///api/login_check
headers :
Content-Type : application/json
body :
{"account":"myLogin","password":"myPassword"}

它将返回类似的内容

{
   "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTZWJrXFxTbWFsbFN3b2Z0QXV0aFxcU2VydmljZVxcQXV0aExvZ2ljIiwic3ViIjoiODciLCJpYXQiOjE2MzQ3MzY2MzIsImV4cCI6MTYzNDgyMzAzMiwiZGF0YSI6eyJ1c2VyIjp7ImlkVXRpbGlzYXRldXIiOjg3LCJpZEdyb3VwIjoxMiwibm9tVXRpbGlzYXRldXIiOiJLVVMiLCJwcmVub21VdGlsaXNhdGV1ciI6IlNcdTAwZTliYXN0aWVuIiwibG9naW5VdGlsaXNhdGV1ciI6IktTIiwicGFzc3dvcmRVdGlsaXNhdGV1ciI6IjVhZWRmN2M4OWNjMzFlZjRmMzQ1ZWViY2U0YTNjZjkxIiwiaWRUeXBlQ29tbWFuZGVVdGlsaXNhdGV1ciI6MSwiZGF0ZUNvbm5leGlvblV0aWxpc2F0ZXVyIjoiMjAyMS0wOC0yMyAxNjoxMToxOCIsImlkRW50cmVwb3RVdGlsaXNhdGV1ciI6MSwiZW1haWxVdGlsaXNhdGV1ciI6Imsuc2ViYXN0aWVuQGxhLWJlY2FuZXJpZS5jb20iLCJ1dGlsaXNhdGV1ckdyb3VwIjpudWxsLCJ1dGlsaXNhdGV1cnNGb25jdGlvbm5hbGl0ZXMiOltdLCJ1dGlsaXNhdGV1cnNSb2xlcyI6W10sImNvdWxldXIiOiIjMzBmY2NjIiwiY291bGV1clN0eWxlIjoiYmFja2dyb3VuZC1jb2xvcjogIzMwZmNjYzsgY29sb3I6d2hpdGU7IiwiZnJvbURiIjp0cnVlfX19.uHcBGGQcc4hhSwcqdBFyci31DI0yeGMq4teD1zURmIE",
   "expired_at": 1634823032
}

或者,如果登录或密码错误,将返回 401 响应

现在,为了访问受保护的路由,请使用带有登录响应令牌的 Authorization 标头。

对于我们的客户列表路由,请使用

GET https:///api/customers/page/1/pageSize/10
headers :
Authorization : Bearer eyJpc3MiOiJTZWJrXFxTbWFsbFN3b2Z0QXV0aFxcU2VydmljZVxcQXV0aExvZ2ljIiwic3ViIjoiODciLCJpYXQiOjE2MzQ3MzA2NDgsImV4cCI6MTYzNDgxNzA0OCwiZGF0YSI6eyJ1c2VyIjp7ImlkVXRpbGlzYXRldXIiOjg3LCJpZEdyb3VwIjoxMiwibm9tVXRpbGlzYXRldXIiOiJLVVMiLCJwcmVub21VdGlsaXNhdGV1ciI6IlNcdTAwZTliYXN0aWVuIiwibG9naW5VdGlsaXNhdGV1ciI6IktTIiwicGFzc3dvcmRVdGlsaXNhdGV1ciI6IjVhZWRmN2M4OWNjMzFlZjRmMzQ1ZWViY2U0YTNjZjkxIiwiaWRUeXBlQ29tbWFuZGVVdGlsaXNhdGV1ciI6MSwiZGF0ZUNvbm5leGlvblV0aWxpc2F0ZXVyIjoiMjAyMS0wOC0yMyAxNjoxMToxOCIsImlkRW50cmVwb3RVdGlsaXNhdGV1ciI6MSwiZW1haWxVdGlsaXNhdGV1ciI6Imsuc2ViYXN0aWVuQGxhLWJlY2FuZXJpZS5jb20iLCJ1dGlsaXNhdGV1ckdyb3VwIjpudWxsLCJ1dGlsaXNhdGV1cnNGb25jdGlvbm5hbGl0ZXMiOltdLCJ1dGlsaXNhdGV1cnNSb2xlcyI6W10sImNvdWxldXIiOiIjMzBmY2NjIiwiY291bGV1clN0eWxlIjoiYmFja2dyb3VuZC1jb2xvcjogIzMwZmNjYzsgY29sb3I6d2hpdGU7IiwiZnJvbURiIjp0cnVlfX19.dTW8L2RyNv9OnhXHu96UCEKL3UpHJj3mXLJdf_LD-yI

如果成功,服务器将返回 200 状态码,如果令牌错误或过期,则返回 401 状态码。