axios解决oauth2跨域问题
最近因为这个问题耗费了几天时间,觉得可能大家以后工作中有可能碰到,所以记录下来前端是VUE框架的axios请求模式,后端采用springboot做的一个授权和认证服务postman一切正常,然后开始联调发生悲剧!前端说后端有问题,跨域没解决,开始动手,先解决认证服务器跨域问题一般先在WebSecurityConfigurerAdapter实现里添加允许跨域@Override...
最近因为这个问题耗费了几天时间,觉得可能大家以后工作中有可能碰到,所以记录下来
前端是VUE框架的axios请求模式,后端采用springboot做的一个授权和认证服务
postman一切正常,然后开始联调发生悲剧!
前端说后端有问题,跨域没解决,开始动手,先解决认证服务器跨域问题
一般先在WebSecurityConfigurerAdapter实现里添加允许跨域
@Override
protected void configure(HttpSecurity http) throws Exception {
http
...
.and().cors()
.and().csrf().disable()
;
}
发现不起作用,参考源码问题提问中搜索cors的问题,发现有专门的文档说明,于是添加
@Bean
CorsConfigurationSource corsConfigurationSource(){
CorsConfiguration corsConfiguration=new CorsConfiguration();
corsConfiguration.setAllowedOrigins(Arrays.asList("http://localhost:8016/oauth/token"));
corsConfiguration.setAllowedMethods(Arrays.asList("POST, GET, OPTIONS, DELETE, PUT, HEAD"));
UrlBasedCorsConfigurationSource source =new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfiguration);
return source;
}
发现还是不起作用,然后前端就说跨域请求头报错(他只知道跨域问题,很简单的,至少他这么认为),索性尝试换另外一种思路,有没有cors关于请求头的拦截器呢(因为接口没有涉及log,所以想加个拦截器看看,至少保证前端传递的参数是正确的),找到了
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.setAllowCredentials(true);
config.addAllowedMethod("*");
config.addAllowedHeader("*");
config.addExposedHeader("Authorization");
config.addExposedHeader("Content-Disposition");
config.addExposedHeader("Content-Type");
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
return new CorsFilter(configSource);
}
}
发现功能和上面一个配置有点像,继续找新的 WebMvcConfigurationSupport也有同样配置
@Slf4j
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("X-Access-Token");
log.debug("允许跨域配置成功!");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CrossInterceptor()).addPathPatterns("/**");
log.debug("跨域拦截器注册成功!");
}
}
还是不行,头有点懵(心里有点没底),然后决定第二天重新来试
新的一天新思路,找到前端然后硬着头皮让他起服务(估计他心里觉得我存粹在瞎折腾),无意识的点了下他的请求,
OPTIONS,发现都在401错误,然后闲聊发现它的请求方式和我们常见的ajax和js还是有点不同
return axios({
url: 'http://192.168.1.136:8016/oauth/token',
method: 'post',
data: data,
]
})
axios,然后就专门搜了这个请求模式。发现在修改请求头模式下,都会发送一个预请求OPTIONS,然后还真被我发现,原来只有预请求正确的情况下才会有正式的请求,于是添加拦截器,如果预请求成功,就更改响应状态
@Log4j2
@Configuration
@ConfigurationProperties(prefix = "cross")
public class CrossInterceptor implements HandlerInterceptor {
private static List<String> allowHosts;
//配置允许跨域的域名
public void setAllow(String allow) {
if (allow != null) {
allowHosts = Arrays.asList(allow.split(","));
}
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String origin = request.getHeader(HttpHeaders.ORIGIN);
if (origin != null) {
if (allowHosts.contains(origin)) {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT, HEAD");
if(request.getMethod().equals("OPTIONS")){
response.setHeader("Access-Control-Allow-Headers", "Content-Type");
response.setStatus(HttpServletResponse.SC_OK);
}else{
response.setHeader("Access-Control-Allow-Headers", "*");
}
} else {
log.warn("跨域失败:" + origin);
}
}
return true;
}
}
配置文件
cross: allow: http://192.168.1.155:8080,http://localhost:136,http://localhost:8080
还是401,也亏的是心态好(问题始终要解决),仔细观察发现,预请求居然过了,被拦截的是post,然后继续。。。。
耐心发现还是有收获的,401状态有返回响应UnAuthorization ,虽然内心有一万种觉得是前端请求有问题(他今天被我折腾的心态崩了),但还是忍住了,过一天再问
第三天了,继续看关于oauth2源码内容,既然要证明前端有问题,必须给出证据(以理服人),不是接口问题吗,找到源码接口/oauth/token,DEBUG模式开启!
心平气和又找他谈话去,然后他改正,发现还是有问题,直接找了份百度正规的截图给他
axios({
url: '/user',
method: 'post',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
},
transformRequest: [function (data) {
// Do whatever you want to transform the data
let ret = ''
for (let it in data) {
ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
}
return ret
}],
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
然后进行对比,Content-Type,发现表单提交类型不对,难怪没参数(这里也不是一步发现的),然后改正,终于不报错了,总算送了口气!
下午接着调试资源服务,加上cors拦截器配置,还是出了问题!
{
"code": "1003",
"data": "",
"message": "用户未登录或长时间未操作,请重新登录"
}
虽然自己准确知道了问题的来源(这个异常就是我封装的),但是前端已经完全处于不信任和情绪状态,只能截图给他了,不敢说他错误,就说让他把传参改成固定参数,我测试下其他(自己先测试发现正常),结果改正后他自己发现正确了,然后他又说了一大堆。。。
这次问题自己总结出几个道理
1遇到问题真的需要的不是技术,是耐心和细心,希望自己能保持它
2证据比什么都总要,在让别人承认错误的时候,永远不要陷入怀疑中
3与人沟通不要跟着别人节奏走,心态要保持不受影响
更多推荐
所有评论(0)