mirror of
https://github.com/halo-dev/docs.git
synced 2025-10-20 17:54:01 +00:00
refactor: update permission control docs for plugin (#443)
### What this PR does? 重构权限控制部分文档并调整相应结构 ```release-note None ```
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
---
|
||||
title: Web 过滤器
|
||||
description: 为 Web 请求提供过滤器扩展点,可用于对请求进行拦截、修改等操作。
|
||||
---
|
||||
|
||||
在现代的 Web 应用开发中,过滤器(Filter)是一个非常重要的概念。你可以使用 `run.halo.app.security.AdditionalWebFilter` 在服务器处理请求之前或之后执行特定的任务。
|
||||
|
||||
通过实现这个接口,开发者可以自定义过滤逻辑,用于处理进入和离开应用程序的 HTTP 请求和响应。
|
||||
|
||||
AdditionalWebFilter 能做什么?
|
||||
|
||||
1. 认证与授权: AdditionalWebFilter 可以用来检查用户是否登录,或者是否有权限访问某个资源。
|
||||
2. 日志记录与审计: 在请求处理之前或之后记录日志,帮助了解应用程序的使用情况。
|
||||
3. 请求重构: 修改请求数据,例如添加、删除或修改请求头或请求参数。
|
||||
4. 响应处理: 修改响应,例如设置通用的响应头。
|
||||
5. 性能监控: 记录处理请求所需的时间,用于性能分析。
|
||||
6. 异常处理: 统一处理请求过程中抛出的异常。
|
||||
7. ......
|
||||
|
||||
## 使用示例
|
||||
|
||||
以下是一个使用 `AdditionalWebFilter` 来拦截 `/login` 请求实现用户名密码登录的示例:
|
||||
|
||||
```java
|
||||
@Component
|
||||
public class UsernamePasswordAuthenticator implements AdditionalWebFilter {
|
||||
final ServerWebExchangeMatcher requiresMatcher = ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, "/login");
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Mono<Void> filter(@NonNull ServerWebExchange exchange, @NonNull WebFilterChain chain) {
|
||||
return this.requiresAuthenticationMatcher.matches(exchange)
|
||||
.filter((matchResult) -> {
|
||||
return matchResult.isMatch();
|
||||
}).flatMap((matchResult) -> {
|
||||
return this.authenticationConverter.convert(exchange);
|
||||
}).switchIfEmpty(chain.filter(exchange)
|
||||
.then(Mono.empty()))
|
||||
.flatMap((token) -> {
|
||||
return this.authenticate(exchange, chain, token);
|
||||
}).onErrorResume(AuthenticationException.class, (ex) -> {
|
||||
return this.authenticationFailureHandler.onAuthenticationFailure(new WebFilterExchange(exchange, chain), ex);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return SecurityWebFiltersOrder.FORM_LOGIN.getOrder();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
1. `filter` 方法中的 `chain.filter(exchange)` 表示继续执行后续的过滤器,如果不调用这个方法,请求将不会继续执行后续的过滤器或目标处理程序。
|
||||
2. `getOrder` 方法用于指定过滤器的执行顺序,比如 `SecurityWebFiltersOrder.FORM_LOGIN.getOrder()` 表示在 Spring Security 的表单登录过滤器之前执行,参考:[SecurityWebFiltersOrder](https://github.com/spring-projects/spring-security/blob/main/config/src/main/java/org/springframework/security/config/web/server/SecurityWebFiltersOrder.java)。
|
||||
|
||||
`AdditionalWebFilter` 对应的 `ExtensionPointDefinition` 如下:
|
||||
|
||||
```yaml
|
||||
apiVersion: plugin.halo.run/v1alpha1
|
||||
kind: ExtensionPointDefinition
|
||||
metadata:
|
||||
name: additional-webfilter
|
||||
spec:
|
||||
className: run.halo.app.security.AdditionalWebFilter
|
||||
displayName: AdditionalWebFilter
|
||||
type: MULTI_INSTANCE
|
||||
description: "Contract for interception-style, chained processing of Web requests that may be used to
|
||||
implement cross-cutting, application-agnostic requirements such as security, timeouts, and others."
|
||||
```
|
||||
|
||||
即声明 `ExtensionDefinition` 自定义模型对象时对应的 `extensionPointName` 为 `additional-webfilter`。
|
||||
|
||||
以下是一些可以参考的项目示例:
|
||||
|
||||
- [OAuth2 第三方登录插件](https://github.com/halo-sigs/plugin-oauth2)
|
||||
- [Halo 用户名密码登录](https://github.com/halo-dev/halo/blob/main/application/src/main/java/run/halo/app/security/authentication/login/UsernamePasswordAuthenticator.java)
|
@@ -0,0 +1,55 @@
|
||||
---
|
||||
title: 附件存储
|
||||
description: 为附件存储方式提供的扩展点,可用于自定义附件存储方式。
|
||||
---
|
||||
附件存储策略扩展点支持扩展附件的上传和存储方式,如将附件存储到第三方云存储服务中。
|
||||
|
||||
扩展点接口如下:
|
||||
|
||||
```java
|
||||
public interface AttachmentHandler extends ExtensionPoint {
|
||||
|
||||
Mono<Attachment> upload(UploadContext context);
|
||||
|
||||
Mono<Attachment> delete(DeleteContext context);
|
||||
|
||||
default Mono<URI> getSharedURL(Attachment attachment,
|
||||
Policy policy,
|
||||
ConfigMap configMap,
|
||||
Duration ttl) {
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
default Mono<URI> getPermalink(Attachment attachment,
|
||||
Policy policy,
|
||||
ConfigMap configMap) {
|
||||
return Mono.empty();
|
||||
}
|
||||
```
|
||||
|
||||
- `upload` 方法用于上传附件,返回值为 `Mono<Attachment>`,其中 `Attachment` 为上传成功后的附件对象。
|
||||
- `delete` 方法用于删除附件,返回值为 `Mono<Attachment>`,其中 `Attachment` 为删除后的附件对象。
|
||||
- `getSharedURL` 方法用于获取附件的共享链接,返回值为 `Mono<URI>`,其中 `URI` 为附件的共享链接。
|
||||
- `getPermalink` 方法用于获取附件的永久链接,返回值为 `Mono<URI>`,其中 `URI` 为附件的永久链接。
|
||||
|
||||
`AttachmentHandler` 对应的 `ExtensionPointDefinition` 如下:
|
||||
|
||||
```yaml
|
||||
apiVersion: plugin.halo.run/v1alpha1
|
||||
kind: ExtensionPointDefinition
|
||||
metadata:
|
||||
name: attachment-handler
|
||||
spec:
|
||||
className: run.halo.app.core.extension.attachment.endpoint.AttachmentHandler
|
||||
displayName: AttachmentHandler
|
||||
type: MULTI_INSTANCE
|
||||
description: "Provide extension points for attachment storage strategies"
|
||||
```
|
||||
|
||||
即声明 `ExtensionDefinition` 自定义模型对象时对应的 `extensionPointName` 为 `attachment-handler`。
|
||||
|
||||
可以参考以下项目示例:
|
||||
|
||||
- [S3 对象存储协议的存储插件](https://github.com/halo-dev/plugin-s3)
|
||||
- [阿里云 OSS 的存储策略插件](https://github.com/halo-sigs/plugin-alioss)
|
||||
- [又拍云 OSS 的存储策略](https://github.com/AirboZH/plugin-uposs)
|
@@ -0,0 +1,81 @@
|
||||
---
|
||||
title: 认证安全过滤器
|
||||
description: 提供 Security WebFilter 扩展点,插件可实现自定义认证逻辑,例如:用户名密码认证,JWT 认证,匿名认证。
|
||||
---
|
||||
|
||||
此前,Halo 提供了 AdditionalWebFilter 作为扩展点供插件扩展认证相关的功能。但是近期我们明确了 AdditionalWebFilter
|
||||
的使用用途,故不再作为认证的扩展点。
|
||||
|
||||
目前,Halo 提供了三种认证扩展点:表单登录认证、普通认证和匿名认证。
|
||||
|
||||
## 表单登录(FormLogin)
|
||||
|
||||
示例如下:
|
||||
|
||||
```java
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebFilterChain;
|
||||
import reactor.core.publisher.Mono;
|
||||
import run.halo.app.security.FormLoginSecurityWebFilter;
|
||||
|
||||
@Component
|
||||
public class MyFormLoginSecurityWebFilter implements FormLoginSecurityWebFilter {
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||
// Do your logic here
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## 普通认证(Authentication)
|
||||
|
||||
示例如下:
|
||||
|
||||
```java
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebFilterChain;
|
||||
import reactor.core.publisher.Mono;
|
||||
import run.halo.app.security.AuthenticationSecurityWebFilter;
|
||||
|
||||
@Component
|
||||
public class MyAuthenticationSecurityWebFilter implements AuthenticationSecurityWebFilter {
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||
// Do your logic here
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 匿名认证(Anonymous Authentication)
|
||||
|
||||
示例如下:
|
||||
|
||||
```java
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebFilterChain;
|
||||
import reactor.core.publisher.Mono;
|
||||
import run.halo.app.security.AnonymousAuthenticationSecurityWebFilter;
|
||||
|
||||
@Component
|
||||
public class MyAnonymousAuthenticationSecurityWebFilter
|
||||
implements AnonymousAuthenticationSecurityWebFilter {
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||
// Do your logic here
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
我们在实现扩展点的时候需要注意:如果当前请求不满足认证条件,请一定要调用 `chain.filter(exchange)`,给其他 filter 留下机会。
|
||||
|
||||
后续会根据需求实现其他认证相关的扩展点。
|
@@ -0,0 +1,83 @@
|
||||
---
|
||||
title: 评论主体展示
|
||||
description: 用于在管理端评论列表中展示评论的主体内容。
|
||||
---
|
||||
|
||||
评论主体扩展点用于在管理端评论列表中展示评论的主体内容,评论自定义模型是 Halo 主应用提供的,如果你需要使用评论自定义模型,那么评论会统一
|
||||
展示在管理后台的评论列表中,这时就需要通过评论主体扩展点来展示评论的主体内容便于跳转到对应的页面,如果没有实现该扩展点,那么评论列表中对应的评论的主体会显示为“未知”。
|
||||
|
||||
```java
|
||||
public interface CommentSubject<T extends Extension> extends ExtensionPoint {
|
||||
|
||||
Mono<T> get(String name);
|
||||
|
||||
default Mono<SubjectDisplay> getSubjectDisplay(String name) {
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
boolean supports(Ref ref);
|
||||
|
||||
record SubjectDisplay(String title, String url, String kindName) {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `get` 方法用于获取评论主体,参数 `name` 是评论主体的自定义模型对象的名称,返回值为 `Mono<T>`,其中 `T` 为评论主体对象,它是使用评论的那个自定义模型。
|
||||
- `getSubjectDisplay` 方法用于获取评论主体的展示信息,返回值为 `Mono<SubjectDisplay>`,其中 `SubjectDisplay` 为评论主体的展示信息,包含标题、链接和类型名称,用于在主题端展示评论主体的信息。
|
||||
- `supports` 方法用于判断是否支持该评论主体,返回值为 `boolean`,如果支持则返回 `true`,否则返回 `false`。
|
||||
|
||||
实现该扩展点后,评论列表会通过 `get` 方法将主体的自定义模型对象带到评论列表中,可以配置前端的扩展点来决定如何展示评论主体的信息,参考:[UI 评论来源显示](../ui/comment-subject-ref-create.md)
|
||||
|
||||
例如对于文章是支持评论的,所以文章的评论主体扩展点实现如下:
|
||||
|
||||
```java
|
||||
public class PostCommentSubject implements CommentSubject<Post> {
|
||||
|
||||
private final ReactiveExtensionClient client;
|
||||
private final ExternalLinkProcessor externalLinkProcessor;
|
||||
|
||||
@Override
|
||||
public Mono<Post> get(String name) {
|
||||
return client.fetch(Post.class, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SubjectDisplay> getSubjectDisplay(String name) {
|
||||
return get(name)
|
||||
.map(post -> {
|
||||
var url = externalLinkProcessor
|
||||
.processLink(post.getStatusOrDefault().getPermalink());
|
||||
return new SubjectDisplay(post.getSpec().getTitle(), url, "文章");
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Ref ref) {
|
||||
Assert.notNull(ref, "Subject ref must not be null.");
|
||||
GroupVersionKind groupVersionKind =
|
||||
new GroupVersionKind(ref.getGroup(), ref.getVersion(), ref.getKind());
|
||||
return GroupVersionKind.fromExtension(Post.class).equals(groupVersionKind);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`CommentSubject` 对应的 `ExtensionPointDefinition` 如下:
|
||||
|
||||
```yaml
|
||||
apiVersion: plugin.halo.run/v1alpha1
|
||||
kind: ExtensionPointDefinition
|
||||
metadata:
|
||||
name: comment-subject
|
||||
spec:
|
||||
className: run.halo.app.content.comment.CommentSubject
|
||||
displayName: CommentSubject
|
||||
type: MULTI_INSTANCE
|
||||
description: "Provide extension points for comment subject display"
|
||||
```
|
||||
|
||||
即声明 `ExtensionDefinition` 自定义模型对象时对应的 `extensionPointName` 为 `comment-subject`。
|
||||
|
||||
可以参考其他使用该扩展点的项目示例:
|
||||
|
||||
- [Halo 自定义页面评论主体](https://github.com/halo-dev/halo/blob/main/application/src/main/java/run/halo/app/content/comment/SinglePageCommentSubject.java)
|
||||
- [瞬间的评论主体](https://github.com/halo-sigs/plugin-moments/blob/096b1b3e4a2ca44b6f858ba1181b62eeff64a139/src/main/java/run/halo/moments/MomentCommentSubject.java#L25)
|
@@ -0,0 +1,41 @@
|
||||
---
|
||||
title: 评论组件
|
||||
description: 用于自定义评论组件,可在主题端使用其他评论组件。
|
||||
---
|
||||
评论组件扩展点用于自定义主题端使用的评论组件,Halo 通过插件提供了一个默认的评论组件,如果你需要使用其他的评论组件,那么可以通过实现该扩展点来自定义评论组件。
|
||||
|
||||
```java
|
||||
public interface CommentWidget extends ExtensionPoint {
|
||||
|
||||
String ENABLE_COMMENT_ATTRIBUTE = CommentWidget.class.getName() + ".ENABLE";
|
||||
|
||||
void render(ITemplateContext context, IProcessableElementTag tag,
|
||||
IElementTagStructureHandler structureHandler);
|
||||
}
|
||||
```
|
||||
|
||||
其中 `render` 方法用于在主题端模板中渲染评论组件,参数:
|
||||
|
||||
- `context` 为模板上下文,包含执行模板的上下文:变量、模板数据等。
|
||||
- 参数 `tag` 为 `<halo:comment />` 标签它包含元素的名称及其属性
|
||||
- `structureHandler` 是一个特殊的对象,它允许 `CommentWidget` 向引擎发出指令,指示模板引擎应根据处理器的执行而执行哪些操作。
|
||||
|
||||
`CommentWidget` 对应的 `ExtensionPointDefinition` 如下:
|
||||
|
||||
```yaml
|
||||
apiVersion: plugin.halo.run/v1alpha1
|
||||
kind: ExtensionPointDefinition
|
||||
metadata:
|
||||
name: comment-widget
|
||||
spec:
|
||||
className: run.halo.app.theme.dialect.CommentWidget
|
||||
displayName: CommentWidget
|
||||
type: SINGLETON
|
||||
description: "Provides an extension point for the comment widget on the theme-side."
|
||||
```
|
||||
|
||||
即声明 `ExtensionDefinition` 自定义模型对象时对应的 `extensionPointName` 为 `comment-widget`。
|
||||
|
||||
参考:[Thymeleaf IElementTagProcessor 文档](https://www.thymeleaf.org/doc/tutorials/3.1/extendingthymeleaf.html#element-tag-processors-ielementtagprocessor)。
|
||||
|
||||
参考:[Halo 默认评论组件的实现](https://github.com/halo-dev/plugin-comment-widget/blob/main/src/main/java/run/halo/comment/widget/DefaultCommentWidget.java)。
|
@@ -0,0 +1,65 @@
|
||||
---
|
||||
title: 扩展点
|
||||
description: Halo 服务端为插件提供的扩展点接口
|
||||
---
|
||||
|
||||
术语:
|
||||
|
||||
- 扩展点
|
||||
- 由 Halo 定义的用于添加特定功能的接口。
|
||||
- 扩展点应该在服务的核心功能和它所认为的集成之间的交叉点上。
|
||||
- 扩展点是对服务的扩充,但不是影响服务的核心功能:区别在于,如果没有其核心功能,服务就无法运行,而扩展点对于特定的配置可能至关重要该服务最终是可选的。
|
||||
- 扩展点应该小且可组合,并且在相互配合使用时,可为 Halo 提供比其各部分总和更大的价值。
|
||||
- 扩展
|
||||
- 扩展点的一种具体实现。
|
||||
|
||||
使用 Halo 扩展点的必要步骤是:
|
||||
|
||||
1. 实现扩展点接口,然后标记上 `@Component` 注解。
|
||||
2. 对该扩展点的实现类进行 `ExtensionDefinition` 自定义模型对象的声明。
|
||||
|
||||
例如: 实现一个通知器的扩展,首先 `implements` ReactiveNotifier 扩展点接口:
|
||||
|
||||
```java
|
||||
@Component
|
||||
public class EmailNotifier implements ReactiveNotifier {
|
||||
@Override
|
||||
public Mono<Void> notify(NotificationContext context) {
|
||||
// Send notification
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
然后声明一个 `ExtensionDefinition` 自定义模型对象:
|
||||
|
||||
```yaml
|
||||
apiVersion: plugin.halo.run/v1alpha1
|
||||
kind: ExtensionDefinition
|
||||
metadata:
|
||||
name: halo-email-notifier # 指定一个扩展定义的名称
|
||||
spec:
|
||||
# 扩展的全限定类名
|
||||
className: run.halo.app.notification.EmailNotifier
|
||||
# 所实现的扩展点定义的自定义模型对象名称
|
||||
extensionPointName: reactive-notifier
|
||||
# 扩展名称用于展示给用户
|
||||
displayName: "EmailNotifier"
|
||||
# 扩展的简要描述,用于让用户了解该扩展的作用
|
||||
description: "Support sending notifications to users via email"
|
||||
```
|
||||
|
||||
:::tip Note
|
||||
单实例或多实例的扩展点需要声明对应的 `ExtensionPointDefinition` 自定义模型对象被称之为扩展点定义,用于描述该扩展点的信息,例如:扩展点的名称、描述、扩展点的类型等。
|
||||
|
||||
单实例或多实例扩展点的实现也必须声明一个对应的 `ExtensionDefinition` 自定义模型对象被称之为扩展定义,用于描述该扩展的信息,例如:扩展的名称、描述、对应扩展点的对象名称等。
|
||||
:::
|
||||
|
||||
关于如何在插件中声明自定义模型对象请参考:[自定义模型](../../api-reference/server/extension.md#declare-extension-object)
|
||||
|
||||
以下是目前已支持的扩展点列表:
|
||||
|
||||
```mdx-code-block
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
|
||||
<DocCardList />
|
||||
```
|
@@ -0,0 +1,60 @@
|
||||
---
|
||||
title: 通知器
|
||||
description: 为以何种方式向用户发送通知提供的扩展点。
|
||||
---
|
||||
|
||||
通知器扩展点是用于扩展为 Halo 通知系统提供更多通知方式的扩展点,例如:邮件、短信、WebHook 等。
|
||||
|
||||
```java
|
||||
public interface ReactiveNotifier extends ExtensionPoint {
|
||||
|
||||
Mono<Void> notify(NotificationContext context);
|
||||
}
|
||||
```
|
||||
|
||||
`notify` 方法用于发送通知,参数:context 为通知上下文,包含通知的内容、接收者、通知配置等信息。
|
||||
|
||||
除了实现该扩展点并声明 `ExtensionDefinition` 自定义模型对象外,还需要声明一个 `NotifierDescriptor` 自定义模型对象用于描述通知器,例如:
|
||||
|
||||
```yaml
|
||||
apiVersion: notification.halo.run/v1alpha1
|
||||
kind: NotifierDescriptor
|
||||
metadata:
|
||||
name: default-email-notifier
|
||||
spec:
|
||||
displayName: '邮件通知'
|
||||
description: '通过邮件将通知发送给用户'
|
||||
notifierExtName: 'halo-email-notifier'
|
||||
senderSettingRef:
|
||||
name: 'notifier-setting-for-email'
|
||||
group: 'sender'
|
||||
#receiverSettingRef:
|
||||
# name: ''
|
||||
# group: ''
|
||||
```
|
||||
|
||||
- `notifierExtName` 为通知器扩展的自定义模型对象名称
|
||||
- `senderSettingRef` 用于声明通知器的发送者配置,例如:邮件通知器的发送者配置为:SMTP 服务器地址、端口、用户名、密码等,如果没有可以不配置,参考:[表单定义](../../../form-schema.md)
|
||||
- `name` 为发送者配置的名称,它是一个 `Setting` 自定义模型对象的名称。
|
||||
- `group` 用于引用到一个具体的配置 Schema 组,它是一个 `Setting` 自定义模型对象中描述的 `formSchema` 的 `group`,由于 `Setting` 可以声明多个配置分组但通知器的发送者配置只能有在一个组,因此需要指定一个组。
|
||||
- `receiverSettingRef` 用于声明通知器的接收者配置,例如:邮件通知器的接收者配置为:接收者邮箱地址,如果没有可以不配置,`name` 和 `group` 配置同 `senderSettingRef`。
|
||||
|
||||
当配置了 `senderSettingRef` 后,触发通知时 `notify` 方法的 `context` 参数中会包含 `senderConfig` 即为发送者配置的值,`receiverConfig` 同理。
|
||||
|
||||
`ReactiveNotifier` 对应的 `ExtensionPointDefinition` 如下:
|
||||
|
||||
```yaml
|
||||
apiVersion: plugin.halo.run/v1alpha1
|
||||
kind: ExtensionPointDefinition
|
||||
metadata:
|
||||
name: reactive-notifier
|
||||
spec:
|
||||
className: run.halo.app.notification.ReactiveNotifier
|
||||
displayName: Notifier
|
||||
type: MULTI_INSTANCE
|
||||
description: "Provides a way to extend the notifier to send notifications to users."
|
||||
```
|
||||
|
||||
即声明 `ExtensionDefinition` 自定义模型对象时对应的 `extensionPointName` 为 `reactive-notifier`。
|
||||
|
||||
使用案例可以参考:[Halo 邮件通知器](https://github.com/halo-dev/halo/blob/main/application/src/main/java/run/halo/app/notification/EmailNotifier.java)
|
@@ -0,0 +1,43 @@
|
||||
---
|
||||
title: 主题端文章内容处理
|
||||
description: 提供扩展主题端文章内容处理的方法,干预文章内容的渲染。
|
||||
---
|
||||
|
||||
主题端文章内容处理扩展点用于干预文章内容的渲染,例如:在文章内容中添加广告、添加版权信息等。
|
||||
|
||||
```java
|
||||
public interface ReactivePostContentHandler extends ExtensionPoint {
|
||||
|
||||
Mono<PostContentContext> handle(@NonNull PostContentContext postContent);
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
class PostContentContext {
|
||||
private Post post;
|
||||
private String content;
|
||||
private String raw;
|
||||
private String rawType;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`handle` 方法用于处理文章内容,参数 `postContent` 为文章内容上下文,包含文章自定义模型对象、文章 html 内容、原始内容、原始内容类型等信息。
|
||||
|
||||
`ReactivePostContentHandler` 对应的 `ExtensionPointDefinition` 如下:
|
||||
|
||||
```yaml
|
||||
apiVersion: plugin.halo.run/v1alpha1
|
||||
kind: ExtensionPointDefinition
|
||||
metadata:
|
||||
name: reactive-post-content-handler
|
||||
spec:
|
||||
className: run.halo.app.theme.ReactivePostContentHandler
|
||||
displayName: ReactivePostContentHandler
|
||||
type: MULTI_INSTANCE
|
||||
description: "Provides a way to extend the post content to be displayed on the theme-side."
|
||||
```
|
||||
|
||||
即声明 `ExtensionDefinition` 自定义模型对象时对应的 `extensionPointName` 为 `reactive-post-content-handler`。
|
||||
|
||||
使用案例可以参考:[WebP Cloud 插件](https://github.com/webp-sh/halo-plugin-webp-cloud/blob/a6069dfa78931de0d5b5dfe98fdd18a0da75b09f/src/main/java/se/webp/plugin/WebpCloudPostContentHandler.java#L17)
|
||||
它的作用是处理主题端文章内容中的所有图片的地址,将其替换为一个 WebP Cloud 的代理地址,从而实现文章内容中的图片都使用 WebP 格式。
|
@@ -0,0 +1,38 @@
|
||||
---
|
||||
title: 主题端自定义页面内容处理
|
||||
description: 提供扩展主题端自定义页面内容处理的方法,干预自定义页面内容的渲染。
|
||||
---
|
||||
|
||||
主题端自定义页面内容处理扩展点,作用同 [主题端文章内容处理](./post-content.md) 扩展点,只是作用于自定义页面。
|
||||
|
||||
```java
|
||||
public interface ReactiveSinglePageContentHandler extends ExtensionPoint {
|
||||
|
||||
Mono<SinglePageContentContext> handle(@NonNull SinglePageContentContext singlePageContent);
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
class SinglePageContentContext {
|
||||
private SinglePage singlePage;
|
||||
private String content;
|
||||
private String raw;
|
||||
private String rawType;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`ReactiveSinglePageContentHandler` 对应的 `ExtensionPointDefinition` 如下:
|
||||
|
||||
```yaml
|
||||
apiVersion: plugin.halo.run/v1alpha1
|
||||
kind: ExtensionPointDefinition
|
||||
metadata:
|
||||
name: reactive-singlepage-content-handler
|
||||
spec:
|
||||
className: run.halo.app.theme.ReactiveSinglePageContentHandler
|
||||
displayName: ReactiveSinglePageContentHandler
|
||||
type: MULTI_INSTANCE
|
||||
description: "Provides a way to extend the single page content to be displayed on the theme-side."
|
||||
```
|
||||
|
||||
即声明 `ExtensionDefinition` 自定义模型对象时对应的 `extensionPointName` 为 `reactive-singlepage-content-handler`。
|
@@ -0,0 +1,77 @@
|
||||
---
|
||||
title: 主题端 Halo Footer 标签处理
|
||||
description: 提供扩展主题端 HTML 页面中的 <halo:footer/> 标签内容处理的方法。
|
||||
---
|
||||
|
||||
Halo 为主题端模板提供了自定义标签 `<halo:footer/>` 的处理扩展点,以便可以添加额外的页脚内容如版权信息、备案号等。
|
||||
|
||||
## 使用场景
|
||||
|
||||
- 添加备案号
|
||||
- 添加版权信息
|
||||
- 添加统计代码
|
||||
- 添加自定义脚本
|
||||
- 添加自定义链接
|
||||
|
||||
## 扩展点定义
|
||||
|
||||
扩展 `<halo:footer/>` 标签的扩展点定义为 `TemplateFooterProcessor`,对应的 `ExtensionPoint` 类型为 `MULTI_INSTANCE`,即可以有多个实现类。
|
||||
|
||||
```java
|
||||
public interface TemplateFooterProcessor extends ExtensionPoint {
|
||||
|
||||
Mono<Void> process(ITemplateContext context, IProcessableElementTag tag,
|
||||
IElementTagStructureHandler structureHandler, IModel model);
|
||||
}
|
||||
```
|
||||
|
||||
`TemplateFooterProcessor` 对应的 `ExtensionPointDefinition` 资源描述如下:
|
||||
|
||||
```yaml
|
||||
apiVersion: plugin.halo.run/v1alpha1
|
||||
kind: ExtensionPointDefinition
|
||||
metadata:
|
||||
name: template-footer-processor
|
||||
spec:
|
||||
className: run.halo.app.theme.dialect.TemplateFooterProcessor
|
||||
displayName: 页脚标签内容处理器
|
||||
type: MULTI_INSTANCE
|
||||
description: "提供用于扩展 <halo:footer/> 标签内容的扩展方式。"
|
||||
```
|
||||
|
||||
即声明 `ExtensionDefinition` 自定义模型对象时对应的 `extensionPointName` 为 `template-footer-processor`。
|
||||
|
||||
## 示例实现
|
||||
|
||||
以下是一个简单的 TemplateFooterProcessor 插件实现示例:
|
||||
|
||||
```java
|
||||
@Component
|
||||
public class FakeFooterCodeInjection implements TemplateFooterProcessor {
|
||||
|
||||
@Override
|
||||
public Mono<Void> process(ITemplateContext context, IProcessableElementTag tag,
|
||||
IElementTagStructureHandler structureHandler, IModel model) {
|
||||
var factory = context.getModelFactory();
|
||||
// regular footer text
|
||||
var copyRight = factory.createText("<div>© 2024 Halo</div>");
|
||||
model.add(copyRight);
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
声明 ExtensionDefinition 自定义模型对象时对应的 extensionPointName 为 template-footer-processor。
|
||||
|
||||
```yaml
|
||||
apiVersion: plugin.halo.run/v1alpha1
|
||||
kind: ExtensionDefinition
|
||||
metadata:
|
||||
name: custom-footer-extension
|
||||
spec:
|
||||
extensionPointName: template-footer-processor
|
||||
className: com.example.FakeFooterCodeInjection
|
||||
displayName: "Custom Footer Extension"
|
||||
description: "Adds custom footer content."
|
||||
icon: 'some-icon'
|
||||
```
|
@@ -0,0 +1,87 @@
|
||||
---
|
||||
title: 主题端 HTML Head 标签处理
|
||||
description: 提供扩展主题端 HTML 页面中的 Head 标签内容处理的方法,干预 HTML 页面的 Head 标签内容。
|
||||
---
|
||||
|
||||
主题端 HTML Head 标签处理扩展点的作用是干预 HTML 页面中的 Head 标签内容,可以添加自定义的 CSS、JS 及 meta 标签等,以满足特定的定制化需求。
|
||||
|
||||
## 使用场景
|
||||
|
||||
- **添加自定义样式或脚本**:在 HTML Head 中插入额外的 CSS 文件或 JavaScript 脚本文件,以增强页面的交互性或样式。
|
||||
- **定制 Meta 标签**:为特定页面添加或修改 meta 标签,如描述、作者、关键词等,以提高 SEO 和页面信息的完整性。
|
||||
- **引入第三方库**:引入第三方库(如 Google Fonts、Font Awesome 等),以满足页面的特殊功能或风格需求。
|
||||
- **定制 Open Graph 等社交媒体标签**:为社交媒体分享优化页面标签内容。
|
||||
|
||||
## 扩展点定义
|
||||
|
||||
主题端 HTML Head 标签处理的扩展点定义为 `TemplateHeadProcessor`,对应的 `ExtensionPoint` 类型为 `MULTI_INSTANCE`,即可以有多个实现类。
|
||||
|
||||
```java
|
||||
@FunctionalInterface
|
||||
public interface TemplateHeadProcessor extends ExtensionPoint {
|
||||
|
||||
Mono<Void> process(ITemplateContext context, IModel model,
|
||||
IElementModelStructureHandler structureHandler);
|
||||
}
|
||||
```
|
||||
|
||||
`TemplateHeadProcessor` 对应的 `ExtensionPointDefinition` 资源描述如下:
|
||||
|
||||
```yaml
|
||||
apiVersion: plugin.halo.run/v1alpha1
|
||||
kind: ExtensionPointDefinition
|
||||
metadata:
|
||||
name: template-head-processor
|
||||
spec:
|
||||
className: run.halo.app.theme.dialect.TemplateHeadProcessor
|
||||
displayName: TemplateHeadProcessor
|
||||
type: MULTI_INSTANCE
|
||||
description: "Provides a way to extend the head tag content in the theme-side HTML page."
|
||||
```
|
||||
|
||||
即声明 `ExtensionDefinition` 自定义模型对象时对应的 `extensionPointName` 为 `template-head-processor`。
|
||||
|
||||
## 示例实现
|
||||
|
||||
以下是一个简单的 TemplateHeadProcessor 插件实现示例:
|
||||
|
||||
```java
|
||||
@Component
|
||||
public class CustomHeadProcessor implements TemplateHeadProcessor {
|
||||
|
||||
@Override
|
||||
public Mono<Void> process(ITemplateContext context, IModel model,
|
||||
IElementModelStructureHandler structureHandler) {
|
||||
// 添加自定义 CSS 文件
|
||||
model.add(context.createStandaloneElementTag("link",
|
||||
"rel", "stylesheet",
|
||||
"href", "/custom/styles.css"));
|
||||
|
||||
// 添加自定义 Meta 标签
|
||||
model.add(context.createStandaloneElementTag("meta",
|
||||
"name", "author",
|
||||
"content", "Your Name"));
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
声明 ExtensionDefinition 自定义模型对象时对应的 extensionPointName 为 template-head-processor。
|
||||
|
||||
```yaml
|
||||
apiVersion: plugin.halo.run/v1alpha1
|
||||
kind: ExtensionDefinition
|
||||
metadata:
|
||||
name: custom-head-extension
|
||||
spec:
|
||||
extensionPointName: template-head-processor
|
||||
className: com.example.CustomHeadProcessor
|
||||
displayName: "Custom Head Extension"
|
||||
description: "Adds custom CSS and meta tags to the head section."
|
||||
```
|
||||
|
||||
## 使用此扩展点的插件
|
||||
|
||||
- [集成 highlight.js 为文章提供代码块高亮渲染](https://github.com/halo-sigs/plugin-highlightjs)
|
||||
- [集成 lightgallery.js,支持在内容页面放大显示图片](https://github.com/halo-sigs/plugin-lightgallery)
|
||||
- [Halo 2.0 对 Umami 的集成](https://github.com/halo-sigs/plugin-umami)
|
@@ -0,0 +1,30 @@
|
||||
---
|
||||
title: 用户名密码认证管理器
|
||||
description: 提供扩展用户名密码的身份验证的方法
|
||||
---
|
||||
|
||||
用户名密码认证管理器扩展点用于替换 Halo 默认的用户名密码认证管理器实现,例如:使用第三方的身份验证服务,一个例子是 LDAP。
|
||||
|
||||
```java
|
||||
public interface UsernamePasswordAuthenticationManager extends ExtensionPoint {
|
||||
Mono<Authentication> authenticate(Authentication authentication);
|
||||
}
|
||||
```
|
||||
|
||||
`UsernamePasswordAuthenticationManager` 对应的 `ExtensionPointDefinition` 如下:
|
||||
|
||||
```yaml
|
||||
apiVersion: plugin.halo.run/v1alpha1
|
||||
kind: ExtensionPointDefinition
|
||||
metadata:
|
||||
name: username-password-authentication-manager
|
||||
spec:
|
||||
className: run.halo.app.security.authentication.login.UsernamePasswordAuthenticationManager
|
||||
displayName: Username password authentication manager
|
||||
type: SINGLETON
|
||||
description: "Provides a way to extend the username password authentication."
|
||||
```
|
||||
|
||||
即声明 `ExtensionDefinition` 自定义模型对象时对应的 `extensionPointName` 为 `username-password-authentication-manager`。
|
||||
|
||||
可以参考的实现示例 [TOTP 认证](https://github.com/halo-dev/halo/blob/86e688a15d05c084021b6ba5e75d56a8813c3813/application/src/main/java/run/halo/app/security/authentication/twofactor/totp/TotpAuthenticationFilter.java#L84)
|
Reference in New Issue
Block a user