2020-06 补充: 在Controller中添加了跨域配置的代码,跨域访问的ajax任然失败:反查Controller代码之前filter或者其它早于JFinalFilter执行的过滤器中是否对跨域访问时,浏览器发送http的option(预请求)是否正常处理。具体处理根据自己实际情况修正代码,如果缺乏相关知识,请查询“预检请求(Preflight Request)”。
1 分析:
设置:getResponse().addHeader("Access-Control-Allow-Origin", "*");在不同版本的浏览器中可能报错:
IE报错信息:http://localhost/auth/covert?code=c30643cd-fdfc-4d97-bcc9-eb74046c6d47 的 XMLHttpRequest 需要跨域资源共享(CORS)。
Chrome: jquery-1.11.0.js:9666 Access to XMLHttpRequest at 'http://localhost/auth/covert?code=ca36d3f6-1338-4242-8f7a-fd96e2ada46c' from origin 'http://127.0.0.1:8020' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Failed to load xxxxxxxxxxxxxx : The value of the 'Access-Control-Allow-Origin’ header in the response must not be the wildcard '*’ when the request’s credentials mode is 'include’. Origin 'http://127.0.0.1’ is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
jquery-1.11.0.js:9666 Access to XMLHttpRequest at 'http://localhost/auth/covert?code=4921aab6-7cf1-47f8-8c05-c618e56988b4' from origin 'http://127.0.0.1:8020' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
2 代码实现
模拟各位网友反馈问题后调整后的代码如下:
基于jquery的ajax访问:ajax:function(url,data,callback){
var param={
type:"post",
async:false, // true 异步,false 同步
url:url,
data:data,
dataType:"json",
header:{
token:"abc"
},
error:function(xhr,status,error){
console.log("ajax错误:xhr",xhr);
console.log("ajax错误:status",status);
console.log("ajax错误:error",error);
},
success:function(result,status,xhr){
callback(result);
},
// 下面的两行代码,就是解决跨域的关键
xhrFields: {withCredentials: true},
crossDomain: true
};
$.ajax(param);
}
java代码:Controller的方法上/**
*
* 使用上面生成的code置换token:code只能使用一次
* */
public void covert(String code) {
//String origin=getRequest().getHeader("Origin");
//getResponse().addHeader("Access-Control-Allow-Origin", origin);
//getResponse().addHeader("Access-Control-Allow-Credentials", "true");
//getResponse().addHeader("Access-Control-Allow-Methods","POST,GET,OPTIONS,DELETE"); //支持的http 动作
//getResponse().addHeader("Access-Control-Allow-Headers","simple headers,Accept,Accept-Language,Content-Language,Content-Type,token"); //响应头 请按照自己需求添加。
String origin=getRequest().getHeader("Origin");
getResponse().addHeader("Access-Control-Allow-Origin", origin);
getResponse().addHeader("Access-Control-Allow-Credentials", "true");
getResponse().addHeader("Access-Control-Allow-Methods","*"); //使用通配符
getResponse().addHeader("Access-Control-Allow-Headers","*"); //使用通配符
String token= TokenCache.get(code);
String refresh_token= TokenCache.get(code+"_refresh");
if(token==null) {
renderJson(Response.fail("code过期,置换token失败!"));
}else {
renderJson(Response.ok("token", token).set("refresh_token", refresh_token));
}
}
通过请求,明确跨域的来源。
3 答疑
3.1 header添加token或者Authorization,做前后分离授权
ajax中添加headers,如果不是http协议支持的header,跨域时浏览器安全策略直接阻止发送(观察后台:是否收到http request)。
IE:SCRIPT7002: XMLHttpRequest: 网络错误 0x80070005, 拒绝访问。
Chrome:jquery-1.11.0.js:9666 Access to XMLHttpRequest at 'http://localhost/auth/covert' from origin 'http://127.0.0.1:8020' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
分析:通过浏览器观察先发option请求,为什么呢?其实就是“"预请求"”,即设置Access-Control-Allow-Headers。
3.2 cors-filter第三方库没有使用过
分析一下:如果Tomcat能够部署成功,理论上undertow应该也可以。
配置:cors.propertiescors.allowGenericHttpRequests=true
cors.allowOrigin=*
cors.allowSubdomains=false
cors.supportedMethods=GET, PUT, HEAD, POST, DELETE, OPTIONS
cors.supportedHeaders=Origin, X-Requested-With, Content-Type, Accept, Authorization
cors.exposedHeaders=
cors.supportsCredentials=true
cors.maxAge=3600
UndertowServer启动:UndertowServer server = UndertowServer.create(AppConfig.class);
//配置shiro
server.configWeb(webBuilder -> {
webBuilder.addListener(EnvironmentLoaderListener.class.getName());
webBuilder.addFilter("ShiroFilter", ShiroFilter.class.getName());
webBuilder.addFilterInitParam("ShiroFilter", "configPath", "classpath:shiro.ini");
webBuilder.addFilterUrlMapping("ShiroFilter", "/*", DispatcherType.REQUEST);
webBuilder.addFilterUrlMapping("ShiroFilter", "/*", DispatcherType.FORWARD);
webBuilder.addFilterUrlMapping("ShiroFilter", "/*", DispatcherType.INCLUDE);
webBuilder.addFilterUrlMapping("ShiroFilter", "/*", DispatcherType.ERROR);
// webBuilder.addFilterInitParam("ShiroFilter", "key", "value");
webBuilder.addFilter("CorsFilter", CORSFilter.class.getName());
webBuilder.addFilterInitParam("CorsFilter", "cors.configurationFile", "cors.properties");
webBuilder.addFilterUrlMapping("CorsFilter", "/*", DispatcherType.REQUEST);
webBuilder.addFilterUrlMapping("CorsFilter", "/*", DispatcherType.FORWARD);
webBuilder.addFilterUrlMapping("CorsFilter", "/*", DispatcherType.INCLUDE);
webBuilder.addFilterUrlMapping("CorsFilter", "/*", DispatcherType.ERROR);
});
server.start();