CROS实现跨域时授权问题(401错误)的解决

http://www.open-open.com/lib/view/open1463878276539.html

如果我们访问的资源是不需要授权的,也就是在HTTP请求头中不包含 authentication 头那么以上做法就足够了。但是如果该资源是需要权限验证的,那么这个时候跨域请求的预检测 option 请求,由于不会携带身份信息而被拒绝 。浏览器会报出401错误。

前几天的文章 Spring通过CROS协议解决跨域问题 中提到了如何解决跨域问题的基本思路,解决了跨域请求时浏览器403错误。

Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'null' is therefore not allowed access. 
The response had HTTP status code 403

401错误信息如下:

Failed to load resource:
the server responded with a status of 401 (Unauthorized)
XMLHttpRequest cannot load http://localhost/api/test.
Response for preflight has invalid HTTP status code 401

既然知道了问题的原因,答案也就很容易得出: 对需要进行跨域请求的资源(api),当服务端检测到是 OPTONS 请求时候统统放行,给出HTTP.OK(200)的状态和必要的响应头,哪怕它是不带身份信息的 。

这个问题既可以通过编写对应的后端代码实现,也可以通过设置服务器配置文件实现。也就是如何设置响应头和返回200状态码的办法了。

Spring+Shrio的解决方案

shiro中可以在自己实现的身份验证filter中加入以下代码:

@Override
  protected boolean preHandle(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
      HttpServletRequest request = (HttpServletRequest) servletRequest;
      HttpServletResponse response = (HttpServletResponse) servletResponse;
      if(request.getMethod().equals(RequestMethod.OPTIONS.name()))
      {
          response.setStatus(HttpStatus.OK.value());
          return false;
      }
      return super.preHandle(request, response);
  }

shiro中AccessControlFilter提供了访问控制的基础功能;比如是否允许访问/当访问拒绝时如何处理等,也是我们一般自定义权限验证时候的一个父类,我们通过重写他的 onPreHandle 方法判断是否是 option 请求,如果是则设置相应状态,(响应头已经在之前文章中通过filter配置过了)返回false表示该拦截器实例已经处理了,将直接返回即可。

Tomcat配置

需要修改tomcat的全局web.xml文件在 CATALINA_HOME/conf 下,加入以下配置。

<filter>
       <filter-name>CorsFilter</filter-name>
       <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
     </filter>
     <filter-mapping>
       <filter-name>CorsFilter</filter-name>
       <url-pattern>/*</url-pattern>
     </filter-mapping>

Nginx配置

add_header 'Access-Control-Allow-Methods' 'GET,OPTIONS,PUT,DELETE' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Origin' '$http_origin' always;
add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,User-Agent,Keep-Alive,Content-Type,accept,origin,X-Requested-With' always;

if ($request_method = OPTIONS ) {
    return 200;
}

Apache配置

Header always set Access-Control-Allow-Origin "http://waffle"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS"
Header always set Access-Control-Allow-Credentials "true"
Header always set Access-Control-Allow-Headers "Authorization,DNT,User-Agent,Keep-Alive,Content-Type,accept,origin,X-Requested-With"

RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]

js请求示例

请求时候需要加上 Authorization 和 Content-Type 头。

$http({
  method: 'POST',
  url: scope.webdav.url,
  withCredentials: true,
  headers: {
    Authorization: 'Basic ' + btoa(user + ':' + password),
    'Content-Type': 'application/vnd.google-earth.kml+xml; charset=utf-8'
  },
  data: getKml()

})

### 解决Spring Boot项目中的问题 为了有效解决Spring Boot项目的请求问题,可以采用多种方式来配置CORS(Cross-Origin Resource Sharing)。以下是几种常见的解决方案。 #### 方法一:全局配置CorsConfigurationSource Bean 当需要为整个应用程序设置统一的策略,可以通过定义`CorsConfigurationSource` bean实现。此方法适用于所有控制器接口,并能与Spring Security集成良好[^1]: ```java @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://example.com") // 替换成实际允许的名或IP地址 .allowedMethods("*"); } } ``` 对于更复杂的场景,比如结合Spring安全框架一起工作,则需创建自定义的`CorsConfigurationSource` bean并调用`HttpSecurity.cors()`来进行配置: ```java @Bean public CorsConfigurationSource corsConfigurationSource() { final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin("http://example.com"); // 设置允许的源 config.addAllowedHeader("*"); config.addAllowedMethod("*"); source.registerCorsConfiguration("/**", config); return source; } @Override protected void configure(HttpSecurity http) throws Exception { http.cors().and(); // 启用cors配置 ... } ``` #### 方法二:局部控制@CrossOrigin 注解 如果只想针对特定REST API开放权限,可以在Controller类级别或者具体的方法上添加`@CrossOrigin`注解。这种方式更加灵活,适合不同API有不同的需求的情况[^2]: ```java @RestController @RequestMapping("/api/v1") @CrossOrigin(origins = "http://localhost:8080", maxAge = 3600) public class MyRestController { @GetMapping("/test") public String test(){ return "Hello World!"; } } ``` 需要注意的是,在某些情况下,即使已经按照上述方法进行了正确配置,仍然可能出现失败的现象。这可能是由于浏览器缓存了之前的错误响应所致;也有可能是因为指定的目标URL不完全匹配所造成的。例如,当尝试仅通过IP加端口号的形式(`http://192.168.3.16:9999`)作为允许的起源,可能会遇到兼容性问题。此建议确保路径部分为空,即直接指向Tomcat根目录下的应用实例[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值