Laravel Passport无法处理自有网站的API调用问题
我之前也碰到过一模一样的情况——Password Grant给移动端和第三方调用完全正常,但自家网站的AngularJS Ajax就是卡认证这一步。下面是我一步步排查和解决的方法,应该能帮到你:
1. 先确认中间件的正确注册
CreateFreshApiToken中间件依赖Laravel的session和cookie机制,所以必须把它加到web中间件组里,而不是api组。打开app/Http/Kernel.php,找到$middlewareGroups['web']数组,添加这个中间件:
protected $middlewareGroups = [ 'web' => [ // ... 其他已有的中间件 \Laravel\Passport\Http\Middleware\CreateFreshApiToken::class, ], // ... ];
api组默认是无状态的,不支持这种基于cookie的认证方式,别加错地方了。
2. 调整AngularJS的XSRF头配置
Laravel默认用XSRF-TOKEN cookie存CSRF令牌,但AngularJS默认会把这个令牌放到X-XSRF-TOKEN请求头里,而Laravel的CSRF中间件认的是X-CSRF-TOKEN头。所以得改一下AngularJS的$httpProvider配置:
angular.module('yourAppName', []) .config(['$httpProvider', function($httpProvider) { // 让AngularJS的XSRF设置和Laravel匹配 $httpProvider.defaults.xsrfHeaderName = 'X-CSRF-TOKEN'; $httpProvider.defaults.xsrfCookieName = 'XSRF-TOKEN'; // 如果是子域名跨域调用API,一定要开这个选项 $httpProvider.defaults.withCredentials = true; }]);
这样AngularJS的所有Ajax请求都会自动带上符合Laravel要求的CSRF头。
3. 确保请求携带X-Requested-With头
CreateFreshApiToken中间件只会识别带X-Requested-With: XMLHttpRequest头的请求,然后自动从laravel_token cookie里提取令牌,加到Authorization头里完成认证。
AngularJS默认会给Ajax请求加这个头,但如果你的项目有自定义请求拦截器,要检查有没有把这个头弄丢。如果没带,可以手动加个拦截器补上:
angular.module('yourAppName') .factory('apiInterceptor', function() { return { request: function(config) { config.headers['X-Requested-With'] = 'XMLHttpRequest'; return config; } }; }) .config(['$httpProvider', function($httpProvider) { $httpProvider.interceptors.push('apiInterceptor'); }]);
4. 验证Cookie是否正常生成
用户通过web登录后,打开浏览器的开发者工具检查Cookie,应该能看到两个关键Cookie:
XSRF-TOKEN:由Laravel的VerifyCsrfToken中间件生成的CSRF令牌laravel_token:由CreateFreshApiToken中间件生成的加密认证令牌
如果这两个Cookie不存在,说明你的前端页面路由没有使用web中间件组——确保页面路由在Route::web()里定义,或者手动加上middleware('web')。
5. 确认API路由的认证中间件
你的API路由要使用auth:api中间件,这样CreateFreshApiToken生成的令牌才能被正确识别:
Route::middleware('auth:api')->group(function() { // 这里放需要认证的API路由 });
几个容易踩的坑
- 跨域问题:如果前端和API不在同一个域名(比如子域名),除了AngularJS开
withCredentials,还要在Laravel里配置CORS允许携带Cookie。 - Session驱动:别用
array作为Session驱动(只适合测试),换成file或database等持久化驱动,不然用户登录后Session会直接丢失。 - HTTPS环境:生产环境用HTTPS的话,要在
config/session.php里把'secure'设为true,确保Cookie只能通过HTTPS传输。
按照这些步骤走下来,应该就能解决自家网站AngularJS Ajax的认证问题了。
内容的提问来源于stack exchange,提问作者Dev

