百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

Spring Security怎么实现的跨域? spring跨域解决方案

bigegpt 2024-10-12 05:57 13 浏览

前言

如果你的项目使用了服务网关, 比如Spring Gateway 听我的, 跨域问题在服务网关解决, 如果你的项目没有使用服务网关再考虑在Spring Security解决跨域问题好嘛? (当然我这句话需要按照你的项目实际情况考虑)

至于为什么我要这么说, 我就问问你, Spring Security是不是过滤器? 那Spring Gateway也是不是过滤器? 那谁的过滤器先执行? 谁的过滤器后执行? 如果 Spring Security添加了cors跨域, 但是被Spring Gateway修改了怎么办? 反之又如何?

你必须考虑, 如果Spring Security或者Spring Gateway出现了异常是否会绕过你想象中必须执行的但实际并未执行的过滤器

记住过滤器很好用, 但顺序和执行情况需要严重关切

主要讲了什么?

本篇将介绍跨域问题解决方案, 其中有 Spring 跨域 和 Spring Security跨域问题

基础

什么是跨域?

浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域 域名:

主域名不同 www.baidu.com/index.html -->www.sina.com/test.js

子域名不同 www.666.baidu.com/index.html -->www.555.baidu.com/test.js

域名和域名ip www.baidu.com/index.html -->http://180.149.132.47/test.js

端口:  www.baidu.com:8080/index.html–… www.baidu.com:8081/test.js

协议:  www.baidu.com:8080/index.html–… www.baidu.com:8080/test.js

备注:   1、端口和协议的不同,只能通过后台来解决

2、localhost127.0.0.1虽然都指向本机,但也属于跨域

跨域问题的解决方案都有哪些?

1、客户端浏览器解除跨域限制(理论上可以但是不现实)

2、发送JSONP请求替代XHR请求(并不能适用所有的请求方式,不推荐)

3、修改服务器端(包括HTTP服务器和应用服务器)(推荐

JSONP

JSONP(JSON with Padding)JSON的一种补充使用方式,不是官方协议

JSONP 利用了前端标签的属性src可以访问第三方网站请求并执行的漏洞, 访问第三方网站, 并返回第三方网站的内容

所以站在用户网站来说, 你需要提供:

  • 一个带着 src 属性的标签, 比如 <script> <img> 等, 里面填入跨域服务端的请求地址
    • <script src="http://localhost:8080/jsonp?callback=callback"></script>
  • 一个带着参数的回调函数, 该参数用户接收跨域服务端的数据
    • function callback(data) { console.log(data) alert(data) }
  • 想办法告知跨域服务端, 你的回调函数名(一般放在 src 末尾的 callback 属性上, 比如: http://xxx.com?callback=回调函数名)
    • ?callback=callback // 将回调函数的名字传递给跨域服务端

跨域服务端呢?

  • 需要构建一个controller或者说构建一个请求, 该请求对应着用户网站的 src 地址
    • @GetMapping("jsonp") public void jsonp(@RequestParam("callback") String callback, @RequestParam("hello") String hello, HttpServletResponse response) throws IOException { System.out.println("前端给的数据 hello: " + hello); String data = "我是第三方服务给出的数据"; response.setContentType("text/javascript;charset=UTF-8"); response.getWriter().write(callback + "('" + data + "')"); }
  • 请求需要带上callback字符串
    • String callback,
  • 在该请求的最后返回一个String, 该String返回用户网站的回调函数名(回调函数名(服务端的数据))
    • response.setContentType("text/javascript;charset=UTF-8"); response.getWriter().write(callback + "('" + data + "')"); // 这里返回了一个正在回调函数调用的代码, 并且传递了参数 data

对了如果你得application.yml下有Spring Security的依赖, 可以添加下代码

server:
  port: 8080
spring:
  security:
    user:
      name: zhazha
      password: "{noop}123456"

跨域服务端返回给前端 <script> 标签的字符串将被转化为 callback 函数执行

我们还可以使用 jquery 的方式调用

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>Title</title>
   <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
</head>
<body>
<h1>跨域案例</h1>
<script>
   function callback(data) {
      console.log(data)
      alert(data)
   }
   $.ajax({
      url: "http://localhost:8080/jqJsonp",
      type: "get",
      dataType: "jsonp",
      data: {hello: "hello"},
      jsonp: "callback",
      success: function (data) {
         alert(data)
      },
      error: function () {
         alert("Wrong!")
      }
   });
</script>
</body>
</html>

@GetMapping("jqJsonp")
@ResponseBody
public String jqJsonp(@RequestParam("callback") String callback, @RequestParam("hello") String hello) {
   System.out.println("前端给的数据 hello: " + hello);
   String data = "我是第三方服务给出的数据";
   return callback + "('" + data + "')";
}

总结

jSONP的优点:

  1. 原理简单
  2. 方便快捷, 随时可以搞

JSONP的缺点:

  1. 只支持GET请求
  2. 服务端需要修改代码
  3. 发送的不是 XHR 请求,无法使用 XHR 对象(但这也是为什么可以解决跨域问题的根本)

这项技术在3-4年前可能还有人用, 现在基本上没什么人用, 因为有更好的选择, 但是思路很好

其他方法就不介绍了, 思路差不错, 比如 PostMessage 等方案, 还有一部分借助iframe的, 可能被 Spring Security 拦截, 不好用

CORS跨域资源共享(推荐)

CORS(Cross-Origin Resource Sharing)该技术由 W3C 为浏览器提供了一种跨域资源共享方案

跨域还有什么思路?

可以告诉浏览器, 在两个域名之间开辟一个共享资源空间(或者管道), 这样两个域名就可以进行跨域调用了, 这是一种思路

但是这个共享资源空间肯定是有限制的

共享资源空间, 可以是 header 可以是 cookie, 又或者是 localStore 只要浏览器能够读取到的位置

那么CORS又是怎么实现的呢?

CORS怎么实现的?

CORS新增了一组HTTP请求头字段,通过这些字段,服务器告诉浏览器,哪些网站通过浏览器有权限访问哪些资源。

简单请求(可以不看)

假如站点 https://foo.example 的网页应用想要访问 https://bar.other 的资源。

foo.example 的网页中可能包含类似于下面的 JavaScript 代码:

const xhr = new XMLHttpRequest();
const url = 'https://bar.other/resources/public-data/';

xhr.open('GET', url);
xhr.onreadystatechange = someHandler;
xhr.send();

此操作实行了客户端和服务器之间的简单交换,使用 CORS 首部字段来处理权限:

以下是浏览器发送给服务器的请求报文:

GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example

请求首部字段 Origin 表明该请求来源于 http://foo.example

让我们来看看服务器如何响应:

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml

[…XML Data…]

本例中,服务端返回的 Access-Control-Allow-Origin标头的 Access-Control-Allow-Origin: * 值表明,该资源可以被任意外源访问。

Access-Control-Allow-Origin: *

使用OriginAccess-Control-Allow-Origin 就能完成最简单的访问控制。如果 https://bar.other 的资源持有者想限制他的资源只能通过 https://foo.example 来访问(也就是说,非 https://foo.example 域无法通过跨源访问访问到该资源),他可以这样做:

Access-Control-Allow-Origin: https://foo.example

备注: 当响应的是附带身份凭证的请求时,服务端必须明确 Access-Control-Allow-Origin 的值,而不能使用通配符“*”。

复杂请求(可以不看)

了解有预检请求便可

与简单请求不同,“需预检的请求"要求必须首先使用OPTIONS方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。"预检请求"的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。 如下是一个需要执行预检请求的HTTP请求:

const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://bar.other/resources/post-here/');
xhr.setRequestHeader('X-PINGOTHER', 'pingpong');
xhr.setRequestHeader('Content-Type', 'application/xml');
xhr.onreadystatechange = handler;
xhr.send('<person><name>Arun</name></person>');

上面的代码使用POST请求发送一个XML 请求体,该请求包含了一个非标准的HTTP X-PINGOTHER请求首部。这样的请求首部并不是HTTP/1.1的一部分,但通常对于web应用很有用处。另外,该请求的Content-Typeapplication/xml,且使用了自定义的请求首部,所以该请求需要首先发起“预检请求”。

备注: 如下所述,实际的 POST 请求不会携带 Access-Control-Request-* 首部,它们仅用于 OPTIONS 请求。

下面是服务端和客户端完整的信息交互。首次交互是预检请求/响应

OPTIONS /doc HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type

HTTP/1.1 204 No Content
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive

Copy to Clipboard

从上面的报文中,我们看到,第 1 - 10 行使用 OPTIONS 方法发送了预检请求,浏览器根据上面的JavaScript代码片断所使用的请求参数来决定是否需要发送,这样服务器就可以回应是否可以接受用实际的请求参数来发送请求。OPTIONS 是 HTTP/1.1 协议中定义的方法,用于从服务器获取更多信息,是安全的方法。该方法不会对服务器资源产生影响。注意 OPTIONS 预检请求中同时携带了下面两个首部字段:

Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type

Copy to Clipboard

首部字段 Access-Control-Request-Method 告知服务器,实际请求将使用 POST 方法。首部字段 Access-Control-Request-Headers 告知服务器,实际请求将携带两个自定义请求首部字段:X-PINGOTHERContent-Type。服务器据此决定,该实际请求是否被允许。

第 12 - 21 行为预检请求的响应,表明服务器将接受后续的实际请求方法(POST)和请求头(X-PINGOTHER)。重点看第 15 - 18 行:

Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400

服务器的响应携带了 Access-Control-Allow-Origin: https://foo.example,从而限制请求的源域。同时,携带的 Access-Control-Allow-Methods 表明服务器允许客户端使用 POSTGET 方法发起请求(与 Allow 响应首部类似,但该标头具有严格的访问控制)。

首部字段 Access-Control-Allow-Headers 表明服务器允许请求中携带字段 X-PINGOTHERContent-Type。与 Access-Control-Allow-Methods 一样,Access-Control-Allow-Headers 的值为逗号分割的列表。

最后,首部字段 Access-Control-Max-Age 给定了该预检请求可供缓存的时间长短,单位为秒,默认值是 5 秒。在有效时间内,浏览器无须为同一请求再次发起预检请求。以上例子中,该响应的有效时间为 86400 秒,也就是 24 小时。请注意,浏览器自身维护了一个最大有效时间,如果该首部字段的值超过了最大有效时间,将不会生效。

预检请求完成之后,发送实际请求:

POST /doc HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
X-PINGOTHER: pingpong
Content-Type: text/xml; charset=UTF-8
Referer: https://foo.example/examples/preflightInvocation.html
Content-Length: 55
Origin: https://foo.example
Pragma: no-cache
Cache-Control: no-cache

<person><name>Arun</name></person>

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:40 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 235
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
Content-Type: text/plain

[Some XML payload]

实战

Spring的处理方式

注意, 如果你在项目中引入了 Spring Security, 那么下面几种 Spring 方式可能会报错, 也可能会失效

spring有三种方式处理跨域问题

@CrossOrigin

// 允许 http://localhost:8080 网址的请求
@CrossOrigin(origins = "http://localhost:8080")
@PostMapping("post")
public String post() {
return "hello, post";
}

@CrossOrigin注解各属性含义如下:

  • allowCredentials: 浏览器是否应当发送凭证信息,如Cookie。
  • allowedHeaders: 请求被允许的请求头字段,表示所有字段。
  • exposedHeaders: 哪些响应头可以作为响应的一部分暴露出来。注意,这里只可以一一列举,通配符在这里是无效的。 maxAge: 预检请求的有效期,有效期内不必再次发送预检请求,默认是1800秒。
  • methods: 允许的请求方法,表示允许所有方法。
  • origins: 允许的域,表示允许所有域。

源码分析

  • @CrossOrigin注解在AbstractHandlerMethodMapping 的内部类MappingRegistryregister方法中完成解析的,@CrossOrigin注解中的内容会被解析成一个配置对象CorsConfiguration
  • 将@CrossOrigin所标记的请求方法对象HandlerMethodCorsConfiguration一一对应存入一个名为corsLookupMap集合中。
  • 当请求到达 DispatcherServlet#fdoDispatch 方法之后,调用AbstractHandlerMapping#getHandler方法获取执行链 HandlerExecutionChain时,会从corsLookup集合中获取到CorsConfiguration对象。
  • 根据获取到的CorsConfiguration对象构建一个CorsInterceptor拦截器。
  • CorsInterceptor拦截器中触发对DefaultCorsProcessor#processRequest 的调用,跨域请求的校验工作将在该方法中完成。

全局跨域方式

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class GlobalCorsConfig implements WebMvcConfigurer {

   /**
    * 配置全局跨域解决方案
    *
    * @param registry
    */
   @Override
   public void addCorsMappings(CorsRegistry registry) {
      registry.addMapping("/**")
            .allowedMethods("*")
            .allowedOrigins("*")
            .allowedHeaders("*")
            .allowCredentials(false)
            .exposedHeaders("")
            .maxAge(3600);
   }
}

通过注册CorsFilter的方式

@Bean
public FilterRegistrationBean<CorsFilter> corsFilter() {
  UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
  CorsConfiguration config = new CorsConfiguration();
  config.setAllowCredentials(true);
  config.addAllowedOrigin("*");
  config.addAllowedHeader("*");
  config.addAllowedMethod("*");
  source.registerCorsConfiguration("/**", config);
  FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));
  bean.setOrder(-1); // 这行后面会解释, 为什么?
  return bean;
}

Spring Security处理方案

如果我们配置了 Spring Security的话, 上面的 Spring 解决跨域问题的方式可能失效, 有的还可以使用, 为什么呢?

通过@CrossOrigin注解或者重写addCorsMappings方法配置跨域,统统失效了, 通过CorsFilter 配置的跨域,有没有失效则要看过滤器的优先级,如果过滤器优先级高于Spring Security过滤器,即先于Spring Security过滤器执行,则CorsFilter 所配置的跨域处理依然有效;如果过滤器优先级低于Spring Security过滤器,则CorsFilter 所配置的跨域处理就会失效。这就是为什么我们配置优先级为 -1

意思说, Spring Security你可以看作一个拦截器, 如果 Spring Security优先级高于我们自己配置的cors跨域解决方案(在CorsIntercepter中校验), 那么就会以某些理由拦截下来, 而使得我们配置的跨域失效, 那是为什么呢?

我们知道, 在复杂请求的情况下, 会发送一个预检请求, 但他没有携带任何的认证信息, 直接就会被 Spring Security拦截, 而等到复杂请求发送过来之后, 该请求没有预检请求的信息, 所以也是导致跨域请求失效

如果使用了CorsFilter配置跨域,只要过滤器的优先级高于Spring Security过滤器,即在Spring Security过滤器之前执行了跨域请求校验,那么就不会有问题。如果 CorsFilter的优先级低于Spring Security过滤器,则预检请求一样需要先经过Spring Security过滤器,由于没有携带认证信息,在经过Spring Security过滤器时就会被拦截下来。

那么怎么解决呢?

  • 可以放行 OPTIONS 请求, 但是不安全
  • 可以继续使用前面的 通过注册CorsFilter的方式 这种方式, 只要优先级比Spring Security高就行, 不过那也太不专业了

Spring Security的解决方案

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

   @Override
   protected void configure(HttpSecurity http) throws Exception {
      http
            .authorizeRequests()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .defaultSuccessUrl("/")
            .permitAll()
            .and()
            .cors().configurationSource(configurationSource())
            .and().csrf().disable();
   }

   private UrlBasedCorsConfigurationSource configurationSource() {
      final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
      final CorsConfiguration config = new CorsConfiguration();
      config.setAllowCredentials(true); // 允许cookies跨域
      config.addAllowedOrigin("*");// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
      config.addAllowedHeader("*");// #允许访问的头信息,*表示全部
      config.setMaxAge(18000L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
      config.addAllowedMethod("*");
      source.registerCorsConfiguration("/**", config);
      return source;
   }
}

源码就不分析了, 说白了就是借助上面的方法帮忙 new CorsFilter 过滤器和填充内容

踩坑

我这里呢,给出一些建议,如果你的项目使用的spring gateway,也就是网关的存在,那么你最好跨域就不要在spring security中使用的。直接在spring gateway里面用就可以了。这样会少走很多坑。

因为spring security说白了是过滤器,而spring gateway也是过滤器,这两个过滤器有的时候会串台。

特别是在发现异常的时候。有的时候会绕过双方的拦截器过程直接跳转到异常处理环节,这样就会出现问题。

这里一定要着重关注这一点。他们之间的顺序很重要,出现异常也要防护。

相关推荐

当Frida来“敲”门(frida是什么)

0x1渗透测试瓶颈目前,碰到越来越多的大客户都会将核心资产业务集中在统一的APP上,或者对自己比较重要的APP,如自己的主业务,办公APP进行加壳,流量加密,投入了很多精力在移动端的防护上。而现在挖...

服务端性能测试实战3-性能测试脚本开发

前言在前面的两篇文章中,我们分别介绍了性能测试的理论知识以及性能测试计划制定,本篇文章将重点介绍性能测试脚本开发。脚本开发将分为两个阶段:阶段一:了解各个接口的入参、出参,使用Python代码模拟前端...

Springboot整合Apache Ftpserver拓展功能及业务讲解(三)

今日分享每天分享技术实战干货,技术在于积累和收藏,希望可以帮助到您,同时也希望获得您的支持和关注。架构开源地址:https://gitee.com/msxyspringboot整合Ftpserver参...

Linux和Windows下:Python Crypto模块安装方式区别

一、Linux环境下:fromCrypto.SignatureimportPKCS1_v1_5如果导包报错:ImportError:Nomodulenamed'Crypt...

Python 3 加密简介(python des加密解密)

Python3的标准库中是没多少用来解决加密的,不过却有用于处理哈希的库。在这里我们会对其进行一个简单的介绍,但重点会放在两个第三方的软件包:PyCrypto和cryptography上,我...

怎样从零开始编译一个魔兽世界开源服务端Windows

第二章:编译和安装我是艾西,上期我们讲述到编译一个魔兽世界开源服务端环境准备,那么今天跟大家聊聊怎么编译和安装我们直接进入正题(上一章没有看到的小伙伴可以点我主页查看)编译服务端:在D盘新建一个文件夹...

附1-Conda部署安装及基本使用(conda安装教程)

Windows环境安装安装介质下载下载地址:https://www.anaconda.com/products/individual安装Anaconda安装时,选择自定义安装,选择自定义安装路径:配置...

如何配置全世界最小的 MySQL 服务器

配置全世界最小的MySQL服务器——如何在一块IntelEdison为控制板上安装一个MySQL服务器。介绍在我最近的一篇博文中,物联网,消息以及MySQL,我展示了如果Partic...

如何使用Github Action来自动化编译PolarDB-PG数据库

随着PolarDB在国产数据库领域荣膺桂冠并持续获得广泛认可,越来越多的学生和技术爱好者开始关注并涉足这款由阿里巴巴集团倾力打造且性能卓越的关系型云原生数据库。有很多同学想要上手尝试,却卡在了编译数据...

面向NDK开发者的Android 7.0变更(ndk android.mk)

订阅Google官方微信公众号:谷歌开发者。与谷歌一起创造未来!受Android平台其他改进的影响,为了方便加载本机代码,AndroidM和N中的动态链接器对编写整洁且跨平台兼容的本机...

信创改造--人大金仓(Kingbase)数据库安装、备份恢复的问题纪要

问题一:在安装KingbaseES时,安装用户对于安装路径需有“读”、“写”、“执行”的权限。在Linux系统中,需要以非root用户执行安装程序,且该用户要有标准的home目录,您可...

OpenSSH 安全漏洞,修补操作一手掌握

1.漏洞概述近日,国家信息安全漏洞库(CNNVD)收到关于OpenSSH安全漏洞(CNNVD-202407-017、CVE-2024-6387)情况的报送。攻击者可以利用该漏洞在无需认证的情况下,通...

Linux:lsof命令详解(linux lsof命令详解)

介绍欢迎来到这篇博客。在这篇博客中,我们将学习Unix/Linux系统上的lsof命令行工具。命令行工具是您使用CLI(命令行界面)而不是GUI(图形用户界面)运行的程序或工具。lsoflsof代表&...

幻隐说固态第一期:固态硬盘接口类别

前排声明所有信息来源于网络收集,如有错误请评论区指出更正。废话不多说,目前固态硬盘接口按速度由慢到快分有这几类:SATA、mSATA、SATAExpress、PCI-E、m.2、u.2。下面我们来...

新品轰炸 影驰SSD多款产品登Computex

分享泡泡网SSD固态硬盘频道6月6日台北电脑展作为全球第二、亚洲最大的3C/IT产业链专业展,吸引了众多IT厂商和全球各地媒体的热烈关注,全球存储新势力—影驰,也积极参与其中,为广大玩家朋友带来了...