请问如何实现提供一个对外的服务接口来上传文件?

能否实现一个自己验证安全性的接口给第三方来上传文件到后台。一次调用的HTTP接口(每次带身份信息),不需要每次获取token的那种。能给个思路吗?

CUBA 还是 Jmix?

CUBA里面,谢谢

你好,
考虑以下实现方式

  • 自定义Servlet
    用这种方式的话可以直接将接口定义在 core层,可以省去 web->core的调用过程。但这种方式动作稍大一点,需要自己实现一个 Servlet,自己实现接收文件的 controller,处理安全上下文

  • 基于 RestAPI 文件上传接口
    这种方式还是使用现有的 RestAPI 文件上传接口。添加一个自定义Filter,来构建安全上下文。但是 REST API 的安全机制是通过 XML 配置的,大概看了一下,没有提供扩展的机制。只能使用这个文档 介绍的方式来添加自定义Filter 。

  • 扩展 RestAPI 服务
    参考这里:https://doc.cuba-platform.cn/restapi-7.2-chs/rest_api_v2_custom_controllers.html
    但是有几个配置可以简化一下,如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:security="http://www.springframework.org/schema/security">

    <!-- 在这个包下面定义接收文件的控制器-->
    <context:component-scan base-package="com.company.test.portal.myapi"/>

    <security:http pattern="/rest/myapi/**"
                   create-session="stateless"
                   entry-point-ref="oauthAuthenticationEntryPoint"
                   xmlns="http://www.springframework.org/schema/security">
        <!- 这里将 access 配置为 permitAll,就是不进行身份验证-->
        <intercept-url pattern="/rest/myapi/**" access="permitAll"/>  
        <anonymous enabled="false"/>
        <csrf disabled="true"/>
        <cors configuration-source-ref="cuba_RestCorsSource"/>
        <custom-filter ref="resourceFilter" before="PRE_AUTH_FILTER"/>
    </security:http>
</beans>

以上三种方式,可以先试试第三种。有具体问题再沟通。

2 个赞

感谢答复,我现在是这样干的。我在WEB模块里自定义了一个Spring的RestController来接收文件上传,然后我调用了authenticationService.login来做登录验证,发现SecurityContext没有被设置到上下文,然后手动设置了,不知道这样处理是否正确,有没有什么安全隐患。
有点类似您提到的第一个方案,是否应该移到core层?

Credentials lp = new LoginPasswordCredentials(username, password);
            AuthenticationDetails authenticationDetails = authenticationService.login(lp);
            AppContext.setSecurityContext(new SecurityContext(authenticationDetails.getSession()));

这里你使用匿名会话就行了。刚才再看了一下,可以更简单:

扩展并覆盖 RestAPI 提供的 CubaAnonymousAuthenticationFilter :

public class ExCubaAnonymousAuthenticationFilter extends CubaAnonymousAuthenticationFilter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
       // 在这里根据需要来构建一个匿名安全下文,可以根据 request url 业判断 ,也可以根据自定义的安全规则来判断,比如检测特定的 header、 ip地址等。
      if(xxxxxxx){
              populateSecurityContextWithAnonymousSession();
               chain.doFilter(request,response);
      }else{
           super.doFilter(request, response, chain);
      }
    }
}

然后在 rest-dispatcher-spring.xml 文件中注册扩展的 bean :

<bean id="cuba_AnonymousAuthenticationFilter"
          class="xx.xx..ExCubaAnonymousAuthenticationFilter"/>

这种方式就是我上面说的第二种方式,不用再写控制器接收文件。完全利用 RestAPI 的文件上传接口。

感谢回答,不知道RESTAPI是用的何种方式上传文件的,如果是AJAX的方法,那应该没法传较大的文件吧?大文件用Multipart比较合适点?

Ajax 与 Multipart 是不同的概念。Ajax 指的是调用方式,Multipart 指的传输编码方式。CUBA RestAPI 支持使用 multipart/form-data 格式。

参考 RestAPI 文件上传文档:
https://doc.cuba-platform.cn/restapi-7.2-chs/rest_api_v2_ex_file_upload.html

我意思是我看例子是用ajax方式提交的,ajax方式是不支持multipart/form-data方式吧?有用multipart/form-data提交的例子么?

现代浏览器基本都支持,因为有了 FormData 。具体可以百度一下。

您的意思就是说我用例子里的方式上传一个大文件(1GB),后台处理也可以采用流的方式来处理,不至于占用大量内存。是这样意思吗?我一直以为用ajax上传,是把文件读出来之后转成base64传递的,大文件会爆内存。

是的。是流式处理的。在浏览器支持 FormData 前也不需要base64编码,那时通用的处理方式是自动构建一个 form表单 ,然后提交。

谢谢答复!