Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adapt NON-ADMIN users #7

Merged
merged 9 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,30 @@ AList 存储库插件,支持创建 AList 类型的存储库
## 使用方式

首先[部署一个 AList 服务](https://alist.nn.ci/zh/guide/install/docker.html),进入后台管理,创建存储库

![](docs/img/1.png)
根据文档填写相关信息,注意这里的挂载路径

根据 [AList 文档](https://alist.nn.ci/zh/guide/) 填写相关信息

![](docs/img/2.png)

安装并启用此插件后,在 Halo 后台新建存储策略

![](docs/img/3.png)

选择 AList 存储

![](docs/img/4.png)

根据提示填写以下信息

![](docs/img/5.png)

![](docs/img/6.png)

你填写的用户应该至少拥有以下权限,这里的基本路径就是挂载路径的上级路径

![](docs/img/9.png)
![](docs/img/7.png)

## 注意事项
Expand All @@ -26,6 +40,7 @@ AList 存储库插件,支持创建 AList 类型的存储库
client_max_body_size 0;
```
![](docs/img/8.png)
3. 修改用户状态后需要重新验证来刷新缓存,如:修改用户密码
## 开发环境

插件开发的详细文档请查阅:<https://docs.halo.run/developer-guide/plugin/introduction>
Expand Down Expand Up @@ -55,14 +70,6 @@ cd path/to/plugin-alist

> 此方式需要本地安装 Docker

```bash
# macOS / Linux
./gradlew pnpmInstall

# Windows
./gradlew.bat pnpmInstall
```

```bash
# macOS / Linux
./gradlew haloServer
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ tasks.withType(JavaCompile).configureEach {
}

halo {
version = '2.17'
version = '2.18'
superAdminUsername = 'admin'
superAdminPassword = 'admin'
externalUrl = 'http://localhost:8090'
Expand Down
Binary file added docs/img/10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/img/5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/img/7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/9.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version=1.0.0
version=1.0.1
2 changes: 1 addition & 1 deletion src/main/java/run/halo/alist/config/AListProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class AListProperties {
*/
private String site;
/**
* AList 挂载路径.
* AList 基本路径下文件夹的路径.
*/
private String path;
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
package run.halo.alist.controller;

import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import run.halo.alist.endpoint.AListAttachmentHandler;
import run.halo.alist.config.AListProperties;
import run.halo.alist.dto.AListResult;
import run.halo.alist.dto.response.AListStorageListRes;
import run.halo.alist.dto.request.AListGetFileInfoReq;
import run.halo.alist.dto.response.AListGetCurrentUserInfoRes;
import run.halo.alist.dto.response.AListGetFileInfoRes;
import run.halo.alist.endpoint.AListAttachmentHandler;
import run.halo.alist.exception.AListIllegalArgumentException;
import run.halo.app.plugin.ApiVersion;

Expand All @@ -38,28 +39,68 @@ public Mono<Void> validatePolicyConfig(@RequestBody AListProperties properties)
.flatMap(token -> handler.getWebClients()
.get(properties.getSite())
.get()
.uri("/api/admin/storage/list")
.header("Authorization", token)
.uri("/api/me")
.header(HttpHeaders.AUTHORIZATION, token)
Roozenlz marked this conversation as resolved.
Show resolved Hide resolved
.retrieve()
.bodyToMono(
new ParameterizedTypeReference<AListResult<AListStorageListRes>>() {
new ParameterizedTypeReference<AListResult<AListGetCurrentUserInfoRes>>() {
})
.flatMap(response -> {
if (response.getCode().equals("200")) {
return Flux.fromIterable(response.getData().getContent())
.filter(volume -> Objects.equals(volume.getMountPath(),
properties.getPath()))
.switchIfEmpty(Mono.error(new AListIllegalArgumentException(
"The mount path does not exist")))
.all(volume -> !volume.isDisabled())
.filter(isValid -> isValid)
.switchIfEmpty(Mono.error(new AListIllegalArgumentException(
"The storage is disabled")))
.then();
if (response.getCode().equals("401")) {
return Mono.error(new AListIllegalArgumentException(
"Current user is disabled"));
}
if (!response.getCode().equals("200")) {
return Mono.error(new AListIllegalArgumentException(
"Wrong Username Or Password"));
}
return Mono.error(new AListIllegalArgumentException(
"Wrong Username Or Password"));
}))
AListGetCurrentUserInfoRes userInfo = response.getData();
return handler.getWebClients()
.get(properties.getSite())
.post()
.uri("/api/fs/get")
.header(HttpHeaders.AUTHORIZATION, token)
.body(Mono.just(AListGetFileInfoReq.builder()
.path("/")
.build()),
AListGetFileInfoReq.class)
.retrieve()
.bodyToMono(
new ParameterizedTypeReference<AListResult<AListGetFileInfoRes>>() {
})
.flatMap(res -> {
// 验证当前基本路径是否可用
if (!res.getCode().equals("200")) {
return Mono.error(
new AListIllegalArgumentException(res.getMessage()));
}
// 管理员用户拥有所有权限
if (userInfo.getRole() == 2) {
return Mono.empty();
}
// 普通用户验证权限
int permission = userInfo.getPermission();
StringBuilder sb = new StringBuilder();
if ((permission & 2) == 0) {
sb.append("无需密码访问权限 ");
}
if ((permission & 8) == 0) {
sb.append("创建目录或上传权限 ");
}
if ((permission & 128) == 0) {
sb.append("删除权限 ");
}
if (!sb.isEmpty()) {
sb.append("未开启");
return Mono.error(
new AListIllegalArgumentException(sb.toString()));
}
return Mono.empty();
});

})

)
);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package run.halo.alist.dto.response;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* @author <a href="https://roozen.top">Roozen</a>
* @version 1.0
* 2024/8/2
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AListGetCurrentUserInfoRes {
private int id;
private String username;
private String password;
/**
* 基本路径
*/
@JsonProperty("base_path")
private String basePath;
private int role;
private boolean disabled;
private int permission;
@JsonProperty("sso_id")
private String ssoId;
/**
* 是否开启二步验证
*/
private boolean otp;
}
48 changes: 32 additions & 16 deletions src/main/java/run/halo/alist/endpoint/AListAttachmentHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientRequestException;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UriUtils;
import reactor.core.publisher.Mono;
Expand All @@ -33,6 +34,7 @@
import run.halo.alist.dto.request.AListGetFileInfoReq;
import run.halo.alist.dto.request.AListLoginReq;
import run.halo.alist.dto.request.AListRemoveFileReq;
import run.halo.alist.dto.response.AListGetCurrentUserInfoRes;
import run.halo.alist.dto.response.AListGetFileInfoRes;
import run.halo.alist.dto.response.AListLoginRes;
import run.halo.alist.dto.response.AListUploadAsTaskRes;
Expand Down Expand Up @@ -117,11 +119,8 @@ public Mono<Attachment> upload(UploadContext uploadContext) {
var metadata = new Metadata();
metadata.setName(UUID.randomUUID().toString());
metadata.setAnnotations(
Map.of(Constant.EXTERNAL_LINK_ANNO_KEY,
UriUtils.encodePath(
properties.getSite() + "/d" + properties.getPath() + "/"
+ file.name(),
StandardCharsets.UTF_8)));
Map.of(Constant.EXTERNAL_LINK_ANNO_KEY, ""));

var spec = new Attachment.AttachmentSpec();
SimpleFilePart simpleFilePart = (SimpleFilePart) file;
spec.setDisplayName(simpleFilePart.filename());
Expand Down Expand Up @@ -183,7 +182,9 @@ public Mono<String> auth(AListProperties properties) {
.retrieve()
.bodyToMono(
new ParameterizedTypeReference<AListResult<AListLoginRes>>() {
});
})
.onErrorMap(WebClientRequestException.class,
e -> new AListIllegalArgumentException(e.getMessage()));
}).flatMap(response -> {
if (response.getCode().equals("200")) {
log.info("[AList Info] : Login successfully");
Expand All @@ -198,7 +199,12 @@ public Mono<String> auth(AListProperties properties) {

private AListProperties getProperties(ConfigMap configMap) {
var settingJson = configMap.getData().getOrDefault("default", "{}");
return JsonUtils.jsonToObject(settingJson, AListProperties.class);
AListProperties aListProperties =
JsonUtils.jsonToObject(settingJson, AListProperties.class);
if (aListProperties.getPath().equals("/")) {
aListProperties.setPath("");
}
return aListProperties;
}

@Override
Expand Down Expand Up @@ -264,15 +270,25 @@ public Mono<URI> getPermalink(Attachment attachment, Policy policy, ConfigMap co
}
return Mono.error(new AListRequestErrorException(response.getMessage()));
}))
.map(response -> UriComponentsBuilder.fromHttpUrl(properties.getSite())
.path("/d/{path}/{name}")
.queryParamIfPresent("sign",
Optional.ofNullable(response.getData().getSign()).filter(s -> !s.isEmpty()))
.buildAndExpand(
UriUtils.encodePath(properties.getPath(), StandardCharsets.UTF_8),
UriUtils.encodePath(response.getData().getName(), StandardCharsets.UTF_8)
)
.toUri());
.flatMap(response -> webClients.get(properties.getSite())
.get()
.uri("/api/me")
.header(HttpHeaders.AUTHORIZATION,
tokenCache.getIfPresent(properties.getTokenKey()))
.retrieve()
.bodyToMono(
new ParameterizedTypeReference<AListResult<AListGetCurrentUserInfoRes>>() {
})
.map(res -> UriComponentsBuilder.fromHttpUrl(properties.getSite())
.path("/d{basePath}{path}/{name}")
.queryParamIfPresent("sign",
Optional.ofNullable(response.getData().getSign()).filter(s -> !s.isEmpty()))
.buildAndExpand(
res.getData().getBasePath(),
properties.getPath(),
response.getData().getName()
)
.toUri()));
}

boolean shouldHandle(Policy policy) {
Expand Down
3 changes: 1 addition & 2 deletions src/main/resources/extensions/policy-template-alist.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ spec:
- $formkit: text
name: path
label: 挂载路径
validation: required
help: AList 存储中的挂载路径,必须以 / 开头,如 /aliyun
help: 所填用户基本路径(可在 AList 管理 -> 用户 查看)下文件夹的路径,必须以 / 开头,支持多级目录如 /picture/2024,则全路径为{基本路径}/picture/2024,上传文件时会自动创建不存在的目录,为 / 时留空即可
- $formkit: secret
name: secretName
required: true
Expand Down