Symfony6+React调用API报401未授权,Postman正常前端异常求助
使用Symfony 6和React.js开发时,获取用户购物车数据的API在Postman中测试正常,但前端调用时抛出错误:
401 Unauthorized : A security token is required but the token storage is empty.
此前尝试使用#[CurrentUser]注解也遇到类似问题:Postman正常但前端提示用户未找到,怀疑问题出在security.yaml配置上。
API控制器代码
class PanierController extends AbstractController { public function __construct(TokenStorageInterface $tokenStorage) { $this->tokenStorage = $tokenStorage; } #[Route('/api/get_panier', name: 'get-panier', methods: ['GET','POST'])] public function getPanierContents(TokenInterface $token, Request $request): Response { $token = $this->tokenStorage->getToken(); if (!$token) { return $this->json(['message' => 'Token not found'], Response::HTTP_UNAUTHORIZED); } $user = $token->getUser(); if (!$user || !$user instanceof UserInterface) { $this->logger->error("User not found"); return $this->json(['message' => 'User not found'], Response::HTTP_NOT_FOUND); } error_log("User found: " . $user->getUserIdentifier()); $panier = $user->getPanier(); if (!$panier) { return $this->json(['message' => 'Panier not found'], Response::HTTP_NOT_FOUND); } $billets = $panier->getBillets(); // Convert billets collection to array $billetsArray = []; foreach ($billets as $billet) { $billetsArray[] = [ 'id' => $billet->getId(), 'date_debut_evenementt'=>$billet->getDateDebutEvenement(), // Add other properties you want to include ]; } // $serializedContents = $serializer->serialize($contents, 'json', ['groups' => 'billet']); return $this->json($billetsArray); }
security.yaml配置
app_user_provider: entity: class: App\Entity\Users property: email firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false main: lazy: true provider: app_user_provider custom_authenticator: App\Security\UsersAuthenticator logout: path: app_logout target: connexion_page login: stateless: true json_login: check_path: /api/login username_path: email password_path: password success_handler: lexik_jwt_authentication.handler.authentication_success failure_handler: lexik_jwt_authentication.handler.authentication_failure api: pattern: ^/api stateless: true jwt: ~
React请求代码
export const fetchPanierData = (userId) => { return async (dispatch) => { try { const token = getToken(); if (!token) { throw new Error("No token found"); } const response = await axios.get(`${BASE_URL}/api/get_panier`, { headers: { 'Authorization': `Bearer ${token}`, }, }); dispatch({ type: "FETCH_PANIER_SUCCESS", payload: response.data }); } catch (error) { dispatch({ type: "FETCH_PANIER_FAILURE", payload: error.response ? error.response.data : error.message, }); } }; };
解决方案
1. 调整防火墙匹配顺序
Symfony防火墙是从上到下匹配请求的,原配置中main防火墙在api防火墙之前,main使用会话式认证,而前端请求是无状态的JWT认证,导致请求先匹配到main防火墙后无法获取会话token,返回401。
将login和api防火墙移到main之前,确保/api开头的请求优先匹配JWT认证的防火墙:
firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false login: stateless: true json_login: check_path: /api/login username_path: email password_path: password success_handler: lexik_jwt_authentication.handler.authentication_success failure_handler: lexik_jwt_authentication.handler.authentication_failure api: pattern: ^/api stateless: true jwt: ~ main: lazy: true provider: app_user_provider custom_authenticator: App\Security\UsersAuthenticator logout: path: app_logout target: connexion_page
2. 简化控制器代码(可选)
JWT认证生效后,Symfony会自动解析token并注入当前用户,无需手动从TokenStorage获取:
#[Route('/api/get_panier', name: 'get-panier', methods: ['GET'])] public function getPanierContents(UserInterface $user): Response { $panier = $user->getPanier(); if (!$panier) { return $this->json(['message' => 'Panier not found'], Response::HTTP_NOT_FOUND); } $billets = $panier->getBillets(); $billetsArray = []; foreach ($billets as $billet) { $billetsArray[] = [ 'id' => $billet->getId(), 'date_debut_evenementt'=>$billet->getDateDebutEvenement(), ]; } return $this->json($billetsArray); }
3. 验证前端请求
确认getToken()函数正确获取登录时存储的JWT,且请求头Authorization格式正确(Bearer 后需带空格,无多余字符),可在请求前打印token验证有效性。
内容的提问来源于stack exchange,提问作者Omnia
相关产品推荐
相关产品推荐

