Symfony JSON Login:理解会话认证与令牌认证的本质区别

星浩吖_7488

星浩吖_7488

2026-10-17

148人浏览

原创

Symfony JSON Login:理解会话认证与令牌认证的本质区别

symfony 默认 json 登录使用基于 session 的认证机制(通过 cookie 维持状态),而非无状态 token;若构建真正 restful api,应主动切换为自定义 token 认证器,避免依赖客户端会话存储能力。

symfony 默认 json 登录使用基于 session 的认证机制(通过 cookie 维持状态),而非无状态 token;若构建真正 restful api,应主动切换为自定义 token 认证器,避免依赖客户端会话存储能力。

在 Symfony 中实现 JSON 登录时,初学者常误以为“返回 JSON 就等于无状态 Token 认证”,但事实是:官方 JSON 登录示例默认启用的是 Session-based 认证——即服务器生成并维护一个 PHPSESSID Cookie,前端需在后续请求中自动携带该 Cookie(浏览器默认行为),Symfony 才能识别用户身份。这从 denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY') 能持续生效即可验证。

这种设计对传统 Web 应用合理,但对纯 REST API(如移动端、第三方调用、跨域单页应用)存在明显缺陷:

  • ❌ 无法可靠管理 Cookie(尤其移动端或非浏览器环境)
  • ❌ 违反 REST 无状态(stateless)原则
  • ❌ 横向扩展时需 Session 共享(如 Redis 存储),增加架构复杂度

✅ 正确做法是采用 Token-based 认证:登录成功后返回一个短期有效的、不可预测的令牌(如 UUID),客户端在后续请求的 Authorization 或自定义 Header(如 X-AUTH-TOKEN)中携带,服务端解析并校验,全程不依赖服务端 Session。

以下是实现 Token 认证的核心步骤:

dmap-jsapi-skill
dmap-jsapi-skill

DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。

下载

1. 创建自定义认证器(Symfony 6.2+ 推荐方式)

// src/Security/ApiKeyAuthenticator.php
namespace App\Security;

use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;

class ApiKeyAuthenticator extends AbstractAuthenticator
{
    public function supports(Request $request): ?bool
    {
        return $request->headers->has('X-AUTH-TOKEN');
    }

    public function authenticate(Request $request): Passport
    {
        $token = $request->headers->get('X-AUTH-TOKEN');

        if (empty($token)) {
            throw new CustomUserMessageAuthenticationException('Missing X-AUTH-TOKEN header');
        }

        // 关键:此处应查询数据库验证 token 是否有效、未过期、归属合法用户
        // 示例伪逻辑:$user = $this->tokenRepository->findValidUserByToken($token);
        // 若验证失败,抛出 AuthenticationException 触发 onAuthenticationFailure

        return new SelfValidatingPassport(new UserBadge($token));
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    {
        return null; // 允许请求继续
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
    {
        return new JsonResponse([
            'error' => 'Invalid or expired authentication token'
        ], Response::HTTP_UNAUTHORIZED);
    }
}

⚠️ 注意:UserBadge($token) 仅作占位;真实项目中,你应在 authenticate() 内完成完整校验(如查库、验签名、检查有效期),并返回含用户实体的 Passport(例如配合 PasswordCredentials 或自定义 Badge)。可参考 Symfony 官方自定义认证文档 补充 UserProvider 集成。

2. 在安全配置中启用该认证器

# config/packages/security.yaml
security:
    enable_authenticator_manager: true  # 确保启用新式认证管理器

    firewalls:
        api:
            pattern: ^/api
            security: true
            stateless: true  # ? 强制无状态(禁用 Session)
            custom_authenticators:
                - App\Security\ApiKeyAuthenticator
            # 不再配置 json_login 或 form_login

3. 登录接口:颁发 Token(示例控制器)

// src/Controller/Api/LoginController.php
#[Route('/api/login', methods: ['POST'])]
public function login(Request $request, UserRepository $userRepository, TokenStorageInterface $tokenStorage): JsonResponse
{
    $data = json_decode($request->getContent(), true);
    $email = $data['email'] ?? '';
    $password = $data['password'] ?? '';

    $user = $userRepository->findOneBy(['email' => $email]);
    if (!$user || !password_verify($password, $user->getPassword())) {
        return new JsonResponse(['error' => 'Invalid credentials'], Response::HTTP_UNAUTHORIZED);
    }

    // 生成安全 Token(推荐使用 ramsey/uuid 或 bin2hex(random_bytes(32)))
    $token = Uuid::uuid4()->toString();

    // 持久化 Token(含 user_id、expires_at、is_revoked 等字段)
    $this->tokenRepository->createForUser($user, $token);

    return new JsonResponse(['token' => $token], Response::HTTP_OK);
}

✅ 最佳实践总结

  • 永远不要用 UID、邮箱或明文密码作为 Token —— 必须是加密安全的随机字符串(UUID v4 或 random_bytes(32))
  • Token 必须有时效性与可撤销性 —— 数据库存储 expires_at 和 revoked_at 字段
  • 始终启用 stateless: true —— 确保 Symfony 不启动 Session,避免隐式状态残留
  • 前端必须显式传递 Token —— 如 fetch('/api/profile', { headers: { 'X-AUTH-TOKEN': token } })
  • 敏感操作建议叠加 CSRF(如修改密码) —— 即便无状态,仍需防范跨站请求伪造

通过以上改造,你的 Symfony API 将真正符合 REST 架构约束,具备良好的可扩展性、跨平台兼容性与安全性。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

js json symfony

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
php文件怎么打开
php文件怎么打开

打开php文件步骤:1、选择文本编辑器;2、在选择的文本编辑器中,创建一个新的文件,并将其保存为.php文件;3、在创建的PHP文件中,编写PHP代码;4、要在本地计算机上运行PHP文件,需要设置一个服务器环境;5、安装服务器环境后,需要将PHP文件放入服务器目录中;6、一旦将PHP文件放入服务器目录中,就可以通过浏览器来运行它。

2023.09.01

10844

6

php怎么取出数组的前几个元素
php怎么取出数组的前几个元素

取出php数组的前几个元素的方法有使用array_slice()函数、使用array_splice()函数、使用循环遍历、使用array_slice()函数和array_values()函数等。本专题为大家提供php数组相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.11

6321

5

php反序列化失败怎么办
php反序列化失败怎么办

php反序列化失败的解决办法检查序列化数据。检查类定义、检查错误日志、更新PHP版本和应用安全措施等。本专题为大家提供php反序列化相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.11

2135

5

php怎么连接mssql数据库
php怎么连接mssql数据库

连接方法:1、通过mssql_系列函数;2、通过sqlsrv_系列函数;3、通过odbc方式连接;4、通过PDO方式;5、通过COM方式连接。想了解php怎么连接mssql数据库的详细内容,可以访问下面的文章。

2023.10.23

4008

4

php连接mssql数据库的方法
php连接mssql数据库的方法

php连接mssql数据库的方法有使用PHP的MSSQL扩展、使用PDO等。想了解更多php连接mssql数据库相关内容,可以阅读本专题下面的文章。

2023.10.23

4714

6

html怎么上传
html怎么上传

html通过使用HTML表单、JavaScript和PHP上传。更多关于html的问题详细请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.03

3691

9

PHP出现乱码怎么解决
PHP出现乱码怎么解决

PHP出现乱码可以通过修改PHP文件头部的字符编码设置、检查PHP文件的编码格式、检查数据库连接设置和检查HTML页面的字符编码设置来解决。更多关于php乱码的问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.09

5297

8

php文件怎么在手机上打开
php文件怎么在手机上打开

php文件在手机上打开需要在手机上搭建一个能够运行php的服务器环境,并将php文件上传到服务器上。再在手机上的浏览器中输入服务器的IP地址或域名,加上php文件的路径,即可打开php文件并查看其内容。更多关于php相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.13

4142

8

sprintf函数用法详解
sprintf函数用法详解

sprintf函数的用法:1、格式化字符串;2、指定输出宽度和精度;3、返回值。更多关于sprintf函数用法详解的内容,大家可以阅读下面的文章。

2023.11.27

12042

4

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 21万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 4.8万人学习