WSO2 APIM 4.0.0 Token API添加CORS响应头失败求助
环境:WSO2 APIM 4.0.0,以WSO2 IS 5.11.0作为密钥管理器
前端调用APIM托管API时,浏览器控制台出现CORS错误:
Access to XMLHttpRequest at 'https://apim.mydomain/oauth2/token' from origin 'https://frontendapp.mydomain' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
通过Postman调用https://apim.mydomain/oauth2/token确认响应缺少Access-Control-Allow-Origin头。已尝试配置APIM跳过Token API同步、添加自定义Token API文件、配置IS的CORS规则,但问题未解决。
针对WSO2 APIM 4.0.0 + IS 5.11.0的Token API CORS问题,按以下步骤修正:
1. 修正自定义Token API配置
文件名匹配同步规则
确保自定义API文件名为_TokenAPI_.xml(注意大写的API),与APIM的deployment.toml中跳过列表的_TokenAPI_.xml完全一致,避免因大小写不匹配导致系统自动覆盖自定义配置。
完善API定义(包含OPTIONS预检请求处理)
更新wso2am-4.0.0/repository/deployment/server/synapse-configs/default/api/_TokenAPI_.xml内容,添加OPTIONS方法处理逻辑,并调整Handler顺序:
<?xml version="1.0" encoding="UTF-8"?> <api xmlns="http://ws.apache.org/ns/synapse" name="_WSO2AMTokenAPI_" context="/oauth2/token" binds-to="default"> <!-- 处理POST令牌请求 --> <resource methods="POST" binds-to="default" url-mapping="/*" faultSequence="_token_fault_"> <inSequence> <property name="uri.var.portnum" expression="get-property('keyManager.port')"/> <property name="uri.var.hostname" expression="get-property('keyManager.hostname')"/> <send> <endpoint> <http uri-template="https://{uri.var.hostname}:{uri.var.portnum}/oauth2/token"> <timeout> <duration>60000</duration> <responseAction>fault</responseAction> </timeout> </http> </endpoint> </send> </inSequence> <outSequence> <!-- 为响应添加CORS头 --> <property name="Access-Control-Allow-Origin" value="https://frontendapp.mydomain" scope="transport"/> <property name="Access-Control-Allow-Credentials" value="true" scope="transport"/> <send/> </outSequence> </resource> <!-- 处理OPTIONS预检请求 --> <resource methods="OPTIONS" binds-to="default" url-mapping="/*"> <inSequence> <property name="Access-Control-Allow-Origin" value="https://frontendapp.mydomain" scope="transport"/> <property name="Access-Control-Allow-Methods" value="GET,POST,OPTIONS" scope="transport"/> <property name="Access-Control-Allow-Headers" value="authorization,Content-Type" scope="transport"/> <property name="Access-Control-Allow-Credentials" value="true" scope="transport"/> <respond/> </inSequence> </resource> <handlers> <!-- CORSHandler放在最前面,优先处理预检请求 --> <handler class="org.wso2.carbon.apimgt.gateway.handlers.security.CORSRequestHandler"> <property name="apiImplementationType" value="ENDPOINT"/> <property name="allowHeaders" value="authorization,Content-Type"/> <property name="allowedOrigins" value="https://frontendapp.mydomain"/> <property name="allowedMethods" value="GET,POST,OPTIONS"/> <property name="supportsCredentials" value="true"/> </handler> <handler class="org.wso2.carbon.apimgt.gateway.handlers.common.SynapsePropertiesHandler"/> <handler class="org.wso2.carbon.apimgt.gateway.handlers.ext.APIManagerCacheExtensionHandler"/> </handlers> </api>
注意:将https://frontendapp.mydomain替换为实际前端域名,若无需带凭证请求可使用*,但生产环境建议指定具体域名。
2. 调整APIM的deployment.toml配置
确保跳过列表配置正确,同时添加网关全局CORS配置(可选但推荐):
[apim.sync_runtime_artifacts.gateway.skip_list] apis = ["_OpenService_.xml","_RevokeAPI_.xml", "_TokenAPI_.xml"] # 全局网关CORS配置 [apim.gateway.cors] allow_origins = ["https://frontendapp.mydomain"] allow_methods = ["GET", "POST", "OPTIONS"] allow_headers = ["authorization", "Content-Type"] allow_credentials = true
3. 修正WSO2 IS的CORS配置
由于Token请求最终转发到IS,需添加APIM域名到允许列表:
[cors] allow_generic_http_requests = true allow_any_origin = false allowed_origins = ["https://apim.mydomain", "https://frontendapp.mydomain"] allow_subdomains = false supported_methods = ["GET", "POST", "HEAD", "OPTIONS"] support_any_header = true supported_headers = ["authorization", "Content-Type"] exposed_headers = ["Location", "authorization", "Content-Type"] supports_credentials = true max_age = 3600 tag_requests = false
4. 重启服务并验证
- 先重启WSO2 IS,再重启WSO2 APIM
- 用curl验证OPTIONS预检请求:
curl -X OPTIONS https://apim.mydomain/oauth2/token -H "Origin: https://frontendapp.mydomain" -H "Access-Control-Request-Method: POST" -v
检查响应头是否包含Access-Control-Allow-Origin、Access-Control-Allow-Credentials等字段。
内容的提问来源于stack exchange,提问作者Gustavo Portillo

