---
source: "https://weapp.eteams.cn/build/techdoc/wdoc/index.html#/public/doc/621ea340-1914-4184-b05a-b09fe49ea9ed"
publicId: "621ea340-1914-4184-b05a-b09fe49ea9ed"
---

# 文件服务权限

## 1、文件权限说明

在系统中上传附件后，对附件的操作权限需要由业务模块直接控制。业务模块根据自己的权限体系以及应用场景，进行权限的对接。

## 1.1 附件鉴权规则

 **附件【 根据业务模块 + 附件对应文档权限】的最大权限进行鉴权！！**

附件上传的时候 **module **的参数决定了附件业务模块的归属，后续文件鉴权将根据 **module **对应的业务模块，以及文件生成文档的权限，两者取最大的权限，决定附件是否有权限。

如：上传附件时，**module **参数设置为  ebuilder，文件上传成功后，预览、下载等附件操作时，文件服务会调用 ebuilder 模块对接的权限实现获取是否有对应的权限，再调用附件文档的权限，取最大的权限。

**注意：**

- ** 上传时 ****module 参数需要与 com.weaver.teams.domain.EntityType 枚举类中保持一致。**
- ** 若上传附件时，设置了附件不生成文档，则权限只取业务模块的权限！！！！**

## 1.2 附件鉴权场景

鉴权分为免登场景鉴权和非免登场景鉴权

** 非免登场景鉴权**

附件的权限取【附件业务模块权限和附件所属文档权限的最大权限】。

如：附件module=email，且附件有生成文档，则点击附件预览操作的时，先找email模块获取权限，再找文档模块获取权限，取最大权限

- **登陆情况下，当业务模块****未对接权限时，或者对接权限后权限返回 null 的场景**** ，则走文档模块的权限兜底进行校验，****文档默认只有上传人才有权限**
- **登陆情况下，当业务模块返回没有权限时，若其附件存在文档，则继续走文档鉴权，文档返回有权限则有权限；若其附件没有文档，则按业务模块的权限返回，当业务模块未正常返回权限（异常其情况），则按没有权限处理**

**免登场景鉴权  **

- **免登陆情况下，只走【业务模块鉴权】**
- **免登陆情况下，当未对接权限或者对接权限后权限返回 null 时，直接返回没有权限**

**上传鉴权场景**

- **上传也需要对接权限，当上传传了目录id时，走了业务模块得权限后，会再走文档模块的文件夹权限**

## 2. 附件操作权限类型

- 上传
- 替换附件
- 删除
- 下载
- 预览
- 编辑
- 附件重命名
- 修改密级
- 打印

## 3. 业务模块如何对接权限

1 . 【前置条件】确认好业务模块的 module ，以公共枚举类，com.weaver.teams.domain.EntityType 定义的模块为主。没确认module 参数的业务模块，请再此类中进行定义。后续附件上传的时，module=此参数

2 .  继承 com.weaver.common.mybatis.permission.external.PermissionExternalImpl 方法，在 applicationContext-file-dubbo.xml 定义 rpc 接口属性

- **interface ：值**为： com.weaver.common.mybatis.permission.external.PermissionExternal
- group ：定义规则为：固定前缀 + module， 固定前缀为：weaver.data.permission.
  
  如：文档模块鉴权 module = document ，则 group=weaver.data.permission.document
- ref ：引用的别名，自行定义

完整的设置：

```xml
<dubbo:service ref="file_PermissionExternal" interface="com.weaver.common.mybatis.permission.external.PermissionExternal" group = "weaver.data.permission.document"/>
```

3.  重写方法： `Map\<FileOpType, Boolean\> checkFileRight(Long fileId, Long refId, Long currentEmployeeId, Map\<String, Object\> otherParam);`

- 请求参数说明

| **参数** | **说明** | **备注** |
| --- | --- | --- |
| fileId | 文件id |  |
| refId | 关联附件的业务id，若上传附件的时候，未指定业务id，则鉴权的时候不传此id | 在上传的时候由业务模块自己定义。<br>比如：邮件id和附件id 绑定，上传的时候 refId 传邮件id，上传完成后，可根据邮件id查询到对应的附件，鉴权的时候，也会将此id传给邮件模块，由邮件模块进行判断。 |
| currentEmployeeId | 当前用户id ，**当免登录鉴权时，此值为固定的 -999999L** |  |
| otherParam | 其他鉴权参数 | Map。可以自行获取对应的参数，前提是文件的接口支持了参数的传递，<br>比如：需要传特殊的鉴权参数 source，并且和文件服务约定好了支持此参数透传，则 source 参数会放在 otherParam 里面传给业务模块，业务模块在map中获取权限。已经支持的鉴权参数，请参考 第8节 |

- 返回参数说明

| 参数 | 说明 | 备注 |
| --- | --- | --- |
| Map\<FileOpType, Boolean\> | 返回一个权限map | FileOpType ，权限枚举类，如果返回的Map为 null，或者返回的权限项为 null ，则默认没用对接权限，若附件对应文档存在，此时取附件对应生成的文档的权限。 |

FileOpType  说明

```java
package com.weaver.eteams.file.client.constant;

import java.util.Arrays;

/**
 * @author liyongfeng
 * @ClassName FileOpType.java
 * @Description:
 * @createTime 2021年10月27日 15:07:00
 */
public enum FileOpType {
    /**
     * 下载
     */
    download("download"),
    /**
     * 下载,是否需要文档的鉴权，true，则会继续走文档的权限校验，false ，则不走文档的校验
     */
    downloadDoc("downloadDoc"),
    /**
     * 编辑
     */
    edit("edit"),
    /**
      * 编辑,是否需要文档的鉴权，true，则会继续走文档的权限校验，false ，则不走文档的校验
    */
    editDoc("editDoc"),
    /**
     * 预览
     */
    preview("preview"),
    /**
     * 预览,是否需要文档的鉴权，true，则会继续走文档的权限校验，false ，则不走文档的校验
    */
    previewDoc("previewDoc"),
    /**
     * 删除
     */
    delete("delete"),
     /**
      * 删除,是否需要文档的鉴权，true，则会继续走文档的权限校验，false ，则不走文档的校验
     */
    deleteDoc("deleteDoc"),
    /**
     * 重命名
     */
    rename("rename"),
    /**
     * 重命名,是否需要文档的鉴权，true，则会继续走文档的权限校验，false ，则不走文档的校验
    */
    renameDoc("renameDoc"),
    /**
     * 替换附件
     */
    reupload("reupload"),
    /**
     * 替换附件,是否需要文档的鉴权，true，则会继续走文档的权限校验，false ，则不走文档的校验
    */
    reuploadDoc("reuploadDoc"),
    /**
     * 修改密级
     */
    editSecretLevel("editSecretLevel"),

    old_editSecLevel("editSecLevel"),
     /**
      * 修改密级,是否需要文档的鉴权，true，则会继续走文档的权限校验，false ，则不走文档的校验
     */
    editSecretLevelDoc("editSecretLevelDoc"),
    /**
     * 上传
     */
    upload("upload"),
/**
 * 上传,是否需要文档的鉴权，true，则会继续走文档的权限校验，false ，则不走文档的校验
 */
    uploadDoc("uploadDoc"),

    //打印
    print("print"),
//打印,是否需要文档的鉴权，true，则会继续走文档的权限校验，false ，则不走文档的校验
    printDoc("printDoc"),
    appeal("appeal"),

    /**
     * 是否需要文档的鉴权，true，则会继续走文档的权限校验，false ，则不走文档的校验
     *
     * 默认走文档模块的权限校验
     */
    documentCheck("documentCheck"),

    NONE("")
    ;

}
```

完整的代码示例：（代码示例仅供参考，请按实际业务场景进行对接）

```java
package com.weaver.teams.file.e10.valid;

import java.util.HashMap;
import java.util.Map;

@Service("file_PermissionExternal")
public class DocumentExternalCheck extends PermissionExternalImpl{

    private final Logger logger = LoggerFactory.getLogger(DocumentExternalCheck.class);

    @Autowired
    private DocumentValid documentValid;

    @Override
    public Map<FileOpType, Boolean> checkFileRight(Long fileId, Long refId, Long currentEmployeeId, Map<String, Object> otherParam) {
        logger.info("鉴权中心-文档模块鉴权：fileId={}，refId={}，currentEmployeeId={}，otherParam={}",fileId,refId,currentEmployeeId, Jackson.toJsonString(otherParam));
        Object docObj = otherParam.get("docId");
        Long docId = null;
        if(docObj != null){
            docId = Long.valueOf(String.valueOf(docObj));
        }
        PermissionValue permissionValue = new PermissionValue(fileId,refId,docId, EntityType.document,currentEmployeeId,null);
        permissionValue.setParams(otherParam);
        PermissionType permissionType = documentValid.getDocumentPermission(permissionValue);
        return createRight(permissionType);
    }

    private Map<FileOpType, Boolean> createRight(PermissionType permissionType) {
        Map<FileOpType,Boolean> map = new HashMap<>();
        map.put(FileOpType.upload,permissionType.getUpload());
        map.put(FileOpType.reupload,permissionType.getReupload());
        map.put(FileOpType.rename,permissionType.getRename());
        map.put(FileOpType.preview,permissionType.getPreview());
        map.put(FileOpType.edit,permissionType.getEdit());
        map.put(FileOpType.delete,permissionType.getDelete());
        map.put(FileOpType.download,permissionType.getDownload());
        return map;
    }
}
```

## 4. 如何自定义选择鉴权的模块

当附件的鉴权，需要根据业务场景变更鉴权模块时， 如：当附件上传是，module 设置为公文模块（odoc），此附件被带入到流程中，在流程流转中，就需要流程鉴权了。

**【可以通过 authModule 参数自定义鉴权的模块】**

在上述场景中可以通过 **authModule 来指定流程模块进行鉴权**

** 如：预览操作：**{{host}}/api/file/preview?fileId=7778844911507924529&authModule=workflow

在其他附件操作的接口上，可加入此参数，用来指定对应的业务模块进行鉴权

**注意：**

- **当指定的模块在鉴权白名单中时，此时指定业务模块鉴权将不生效！！！**
  
  **当附件的 module=document 时，通过****authModule 参数指定其他业务模块鉴权的时候，将不再走文档模块鉴权，只有业务模块鉴权。**
- 如果是 post 等接口，此参数要放在请求体中，不要全部都放在 url 上！！！！

## 5. 如何传自定义的鉴权参数

如果需要添加自定义的鉴权参数，可通过 customParam 参数传递，鉴权时在 otherParam 鉴权参数中获取

注意： customParam  是 String 类型！！！

如：某个应用场景，业务模块想要新增鉴权参数myAuth=1234，并在鉴权中获取此参数

则当预览时：/api/file/preview?fileId=7778844911507924529&customParam=myAuth-1234

则在鉴权时，在otherParam 中otherParam.get(“customParam”) 获取此参数的值 myAuth-1234，然后解析成 myAuth=1234

注意：

- 此例子中【 customParam=myAuth-1234】 传参类型和解析类型需要由业务模块自己根据实际情况定义，本示例只是告知怎么传参！！！
- customParam 中切勿传递特殊字符，如 {} \[\] 等可能导致请求失败！！！！
- customParam 的值建议不要用 ecodeUrl 编码，推荐使用base64

## 6.  如何自定义选择鉴权规则

目前的鉴权规则**【当业务模块返回没有权限时，会继续走文档模块的权限，取最大权限】**可能不适合特殊的业务场景鉴权。在某个业务场景下，可能**【只要求做业务模块的鉴】**权

- 业务模块返回权限的时候，可以在 FileOpType 中设上面的权限项是否走文档鉴权，不设置的时候会默认走原逻辑
- documentCheck 是全局控制，这个优先级最高，所有得权限将和文档权限取最大权限

如：在返回权限时，

FileOpType 设置 documentCheck = false，则所有操作的权限不走文档模块鉴权，只走业务模块鉴权

FileOpType  设置 previewDoc=false，则预览时，预览权限不走文档模块鉴权，只走业务模块鉴权

## 7. 当鉴权失败后，如何排查鉴权信息

当出现鉴权不通过提示时，或者怀疑操作已经越权的情况下，请在浏览器中 F12，打开对应的接口，查看鉴权详情（比如预览接口，下载接口等，具体接口请看接口文档）

- ![image.png](https://weapp.eteams.cn/api/file/preview?fileId=1065659434387742762&type=imgs)
  
  data: 鉴权信息主体
- workflow：流程模块鉴权信息
- document： 文档模块鉴权信息
- 注意： 出现两个模块，说明鉴权了两次
- currentEmployeeId： 当前用户id
- moduleId：模块标识
- group：路由的接口
- checkFileRightError：如果鉴权有问题，输出鉴权异常信息
- result: 鉴权的结果，若没用result，则返回的权限是 null

**如果是下载接口，请在下载接口加参数 type=downloadUrl 参数，此时会返回鉴权参数**

## 8. 已支持透传的鉴权参数

| **参数名** | **类型** | **说明** | **备注** |
| --- | --- | --- | --- |
| source | String | 附件来源 | richText(“richText”,”富文本”),form(“form”,”表单模块”),relation(“relation”,”关联附件模块”),comment(“comment”,”评论模块”); |
| objectModule | String | 权限穿透的模块 | 一般用于关联文档的鉴权 |
| objectId | String | 权限穿透的业务id | 一般用于关联文档的鉴权 |
| customParam | String | 自定义鉴权参数 | 可用于传任意类型的参数，鉴权时，将按原样传递给业务模块 |
| refId | Long | 业务id |  |
| docId | Long | 文档id |  |
| authModule | String | 指定鉴权模块 |  |
| fieldId | Long | 字段id | 一般在表单上的附件字段 |

## 9. 富文本文件权限对接

由于文件安全问题，富文本中的文件由【不鉴权逻辑】修改为【需要根据文件的module找对应模块进行反向鉴权】  
【**富文本文件主要涉及操作为预览和下载，其他权限不涉及的建议统一返回 false】**

  
**方案：**

![image.png](https://weapp.eteams.cn/api/file/preview?fileId=1200605876755423242&type=imgs)

**步骤1:  对接文件反向鉴权逻辑，****请参考第3章【业务模块如何对接权限】进行对接，****若已经对接则忽略**

**步骤2: 业务模块需要梳理在哪些功能场景中使用了富文本组件，并且确认在此功能中的富文本文件权限如何实现鉴权，主要涉及的点是：**  
**（1）如何判断此文件是富文本文件**

**：当在富文本中上传文件时，会记录此文件是富文本文件，反向鉴权时在鉴权参数 ****otherParam 中可以获取 source 参数，当source = richText，说明此文件是富文本**

![image.png](https://weapp.eteams.cn/api/file/preview?fileId=1191105756737150978&type=imgs)

**（2）如何判断此富文本文件在哪些业务中**

**：当点击富文本会触发预览接口或者下载接口，推荐使用自定义鉴权参数标记此富文本的业务信息， 反向鉴权时获取自定义鉴权信息，解析业务场景并鉴权。**

![image.png](https://weapp.eteams.cn/api/file/preview?fileId=1191107041051320324&type=imgs)

  
**如果需要添加自定义的鉴权参数，可通过 customParam 参数传递，鉴权时在 otherParam 鉴权参数中获取**

**如：某个应用场景，业务模块想要新增鉴权参数myAuth=1234，并在鉴权中获取此参数**

**则当预览时：/api/file/preview?fileId=7778844911507924529&customParam=myAuth-1234**

**则在鉴权时，在****otherParam 中otherParam.get(“****customParam****”) 获取此参数的值 ****myAuth-1234，然后解析成 myAuth=1234**

**注意： customParam  是 String 类型！！！模块可自定义鉴权参数的内容，并自己解析**

  
**（3）当富文本上传时候设置的module，不符合当前鉴权模块，如何修改鉴权模块**

**当附件的鉴权，需要根据业务场景变更鉴权模块时， 如：当富文本中附件上传时，module 设置为公文模块（odoc），此附件被带入到流程中，在流程流转中，就需要流程鉴权了。**

**【可以通过 authModule 参数自定义鉴权的模块】**

**在上述场景中可以通过 authModule 来指定流程模块进行鉴权**

** 如：预览操作：{{host}}/api/file/preview?fileId=7778844911507924529&authModule=workflow**

**在其他附件操作的接口上，可加入此参数，用来指定对应的业务模块进行鉴权**** **

** (4) 富文本中如何实现自定义参数**

**需要组件支持，咨询富文本组件同事**

[https://weapp.yunteams.cn/ui/rich-text](https://weapp.yunteams.cn/ui/rich-text)  
  
1、复制粘贴图片上传传参： uploadParams  
![aea3c295-9ce4-4ff3-91b7-5f0b46b50fbc.png](https://weapp.eteams.cn/api/file/preview?fileId=1198033040825958412&type=imgs)

2、扩展插件传参：comProps中配置好uploadProps

![76831d74-4a2a-4059-ada5-998e71427825.png](https://weapp.eteams.cn/api/file/preview?fileId=1198033122537562120&type=imgs)

  
3、复写图片预览地址：customImagePreviewUrl 返回复写后的地址

![ae17b71a-3949-4966-942e-f9a25263819f.png](https://weapp.eteams.cn/api/file/preview?fileId=1200785754268164098&type=imgs)

![6f3fb03c-6854-4f6c-91f1-9b96c4c4f628.png](https://weapp.eteams.cn/api/file/preview?fileId=1200785788605390853&type=imgs)

## 10. 多来源权限参数对接

  1、上传接口

URl：/api/file/module/uplaod、/api/app/file/module/uplaod、/papi/file/module/uplaod、/papi/app/file/module/uplaod

参数：

| 参数名称 | 类型 | 说明 |
| --- | --- | --- |
| source | String | 文件来源，富文本传 richText |
| refId | Long | 业务id |
| fieldId | Long | 字段id（可以存储表单字段id） |
| commonText | String | 自定义信息，可以自定义组装信息 |

上传接口中当传  source=richText 时、会将上面的信息都存入到数据库中，鉴权时会查出来给到模块鉴权

 2、预览接口

URL：/api/file/preview 、/api/app/file/preview、/papi/file/preview 、/papi/app/file/preview

 参数：

| 参数名称 | 类型 | 说明 |
| --- | --- | --- |
| sourceRefId | Long | 文件业务Id |
| customParam | String | 前端自定义鉴权参数，不存储，按原样给到业务模块鉴权 |

 sourceRefId 用于匹配业务来源，根据sourceRefId查询是否存在此业务关联的业务来源信息，有则取出来返回给模块鉴权，没有则返回数据中上传时存储的业务来源。
