Angular5+Symfony3授权异常:Postman正常但浏览器返回401
问题诊断与解决方案
看起来你碰到了典型的跨域CORS场景下的认证问题,结合你的配置和浏览器请求头信息,核心原因和解决思路如下:
1. 浏览器CORS预检请求被安全拦截
你在Firefox里看到的是OPTIONS预检请求,这不是实际的登录POST请求——因为你的请求发起自http://sprawy.com,目标是localhost,属于跨域请求,浏览器会先发送OPTIONS请求确认服务器是否允许跨域操作。
而你的security.yml里的login防火墙虽然开放了/api/login路径的匿名访问,但没有明确允许OPTIONS方法,导致这个预检请求被拦截返回401。Postman不会触发浏览器的CORS预检机制,直接发送POST请求,所以能正常拿到Token。
修复步骤:
修改security.yml的login防火墙配置,明确允许OPTIONS方法跳过认证:
firewalls: login: pattern: ^/api/login stateless: true anonymous: true provider: fos_userbundle # 新增这一行,允许OPTIONS方法直接通过 methods: [POST, OPTIONS] form_login: check_path: /api/login_check success_handler: lexik_jwt_authentication.handler.authentication_success failure_handler: lexik_jwt_authentication.handler.authentication_failure require_previous_session: false
2. 缺失CORS响应头配置
即使预检请求通过,服务器还需要返回正确的CORS响应头,告诉浏览器允许跨域的Origin、请求头和方法。你可以通过两种方式配置:
方式一:Apache .htaccess配置
在项目根目录的.htaccess中添加以下规则:
# 允许指定Origin跨域 Header set Access-Control-Allow-Origin "http://sprawy.com" # 允许的请求方法 Header set Access-Control-Allow-Methods "POST, GET, OPTIONS, PUT, DELETE" # 允许自定义请求头 Header set Access-Control-Allow-Headers "Content-Type, Authorization" # 允许携带凭证(如果需要的话) Header set Access-Control-Allow-Credentials "true" # 直接返回200处理OPTIONS预检请求 RewriteEngine On RewriteCond %{REQUEST_METHOD} OPTIONS RewriteRule ^(.*)$ $1 [R=200,L]
方式二:Symfony专用CORS Bundle(推荐)
安装nelmio/cors-bundle后,在config/packages/nelmio_cors.yaml中配置:
nelmio_cors: defaults: origin_regex: false allow_origin: ['http://sprawy.com'] allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE'] allow_headers: ['Content-Type', 'Authorization'] expose_headers: ['Authorization'] max_age: 3600 paths: '^/api/': allow_origin: ['http://sprawy.com'] allow_methods: ['POST', 'GET', 'OPTIONS'] allow_headers: ['Content-Type', 'Authorization'] max_age: 3600
3. 确认请求数据格式匹配
Postman能成功,说明你在Postman中使用的是form-data或application/x-www-form-urlencoded格式提交用户名密码(这是form_login默认支持的格式)。要确保浏览器端的请求也使用相同格式,如果需要支持JSON格式的登录请求,可以修改form_login配置:
form_login: check_path: /api/login_check success_handler: lexik_jwt_authentication.handler.authentication_success failure_handler: lexik_jwt_authentication.handler.authentication_failure require_previous_session: false # 开启JSON格式支持 json_login: username_path: $.username password_path: $.password
内容的提问来源于stack exchange,提问作者Viszman
相关产品推荐
相关产品推荐

