WordPress CORS问题一例
本文记录阿猪在使用WordPress REST API为跨站应用做身份认证时遇到的一例CORS问题。经过一番折腾,最后发现问题出在使用的REST API Authentication插件在处理HTTP请求时与WordPress原生的REST API有重复。
在WordPress的原生REST API中,支持Cookie Authentication和Basic Authentication两种认证方式。然而目前比较主流的认证方式是Json Web Token(简称JWT)和OAuth2.0,需要借助第三方插件实现。以JWT为例,基本逻辑是使用POST方式向生成token的endpoint发送用户名和密码,如果用户名、密码正确,则返回的Headers中会包含token信息,后续使用REST API时,只要每次在Header中包含Authorization: Bearer <json-web-token>
就可以了。
阿猪最先使用的是miniOrange出品的WordPress REST API Authentication插件。在WordPress中和在本地测试请求生成token都正常,但是在跨站应用中测试时,浏览器的控制台却报错:Access to fetch at 'https://yfzhu.cn/wp-json/api/v1/token-validate' from origin 'https://xxx.yfzhu.cn' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
CORS policy是什么鬼?出于安全考虑,浏览器默认会执行同源策略(Same-origin policy),只有同源(URI、主机名、端口相同)的两个页面才被允许相互访问资源。但是在WEB应用中,跨站访问资源是很常见的需求,这就涉及到“跨源资源分享”(Cross-Origin Resource Sharing)的问题。
经过百度和ChatGPT的一通搜索,大部分的回答是说Nginx的配置不正确,没有开启Access-Control-Allow-Origin
这个Header。按照ChatGPT的指导在Nginx的配置文件中添加了相应的Header信息的配置后,可以正常生成token了。以下代码供参考:
1 | http { |
这里顺便说一下,如果你和阿猪一样使用的是OneinStack的LNMP+WordPress全家桶,那么Nginx的配置文件位置是在/usr/local/nginx/conf/vhost/wordpress.conf
,而不是在/usr/local/nginx/conf/nginx.conf
。
但是还没高兴多久,很快又产生了新的问题。阿猪使用生成的jwt通过GET方式向WordPress REST API请求登录用户信息的时候,浏览器的控制台出现如下错误信息:Access to fetch at 'https://yfzhu.cn/wp-json/wp/v2/users/me' from origin 'https://xxx.yfzhu.cn' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values 'https://xxx.yfzhu.cn, https://xxx.yfzhu.cn', but only one is allowed. Have the server send the header with a valid value, or, if an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
后来阿猪想,会不会是WordPress的程序中也有响应Headers信息的语句,从而导致了这个问题。毕竟先前验证token的时候使用的也是GET方法,响应是正常的,没有道理同样是GET请求,服务器区别对待。再仔细对比两个endpoint的路径,一个是第三方插件生成的/wp-json/api/v1/token-validate
,一个是WordPress原生的/wp-json/wp/v2/users/me
。可能是第三方插件和WordPress都在同一个HTTP请求中输出了headers信息,从而导致了重复。搜索了一下WordPress的代码,果然有几个文件中包含Access-Control-Allow-Origin
。
阿猪首先尝试更换JWT插件,毕竟如果换个插件能解决,就可以省去改代码的麻烦了。这次阿猪运气好,换了Enrique Chavez的JWT Authentication for WP-API插件后,问题解决了。如果你也正在被这个问题困扰,希望这篇文章能帮助到你。