mirror of https://github.com/halo-dev/halo
Provide extension points for authentication-related web filters (#5386)
#### What type of PR is this? /kind feature /area core /area plugin /milestone 2.13.x #### What this PR does / why we need it: See https://github.com/halo-dev/halo/issues/5379 for more. This PR provides three extension points: - FormLoginSecurityWebFilter - AuthenticationSecurityWebFilter - AnonymousAuthenticationSecurityWebFilter which could be extended by plugins easily. #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/5379 #### Special notes for your reviewer: TBD. #### Does this PR introduce a user-facing change? ```release-note None ```pull/5400/head
parent
50fbe37be8
commit
bbe79bac10
|
@ -0,0 +1,13 @@
|
|||
package run.halo.app.security;
|
||||
|
||||
import org.pf4j.ExtensionPoint;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
|
||||
/**
|
||||
* Security web filter for anonymous authentication.
|
||||
*
|
||||
* @author johnniang
|
||||
*/
|
||||
public interface AnonymousAuthenticationSecurityWebFilter extends WebFilter, ExtensionPoint {
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package run.halo.app.security;
|
||||
|
||||
import org.pf4j.ExtensionPoint;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
|
||||
/**
|
||||
* Security web filter for normal authentication.
|
||||
*
|
||||
* @author johnniang
|
||||
*/
|
||||
public interface AuthenticationSecurityWebFilter extends WebFilter, ExtensionPoint {
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package run.halo.app.security;
|
||||
|
||||
import org.pf4j.ExtensionPoint;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
|
||||
/**
|
||||
* Security web filter for form login.
|
||||
*
|
||||
* @author johnniang
|
||||
*/
|
||||
public interface FormLoginSecurityWebFilter extends WebFilter, ExtensionPoint {
|
||||
|
||||
}
|
|
@ -14,6 +14,7 @@ import org.springframework.stereotype.Component;
|
|||
* @since 2.0.0
|
||||
*/
|
||||
@Component
|
||||
@Deprecated(forRemoval = true)
|
||||
public class ExtensionComponentsFinder {
|
||||
public static final String SYSTEM_PLUGIN_ID = "system";
|
||||
private final PluginManager pluginManager;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package run.halo.app.plugin.extensionpoint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -86,6 +87,15 @@ public class DefaultExtensionGetter implements ExtensionGetter {
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends ExtensionPoint> Flux<T> getExtensions(Class<T> extensionPointClass) {
|
||||
var extensions = new ArrayList<>(pluginManager.getExtensions(extensionPointClass));
|
||||
applicationContext.getBeanProvider(extensionPointClass)
|
||||
.orderedStream()
|
||||
.forEach(extensions::add);
|
||||
return Flux.fromIterable(extensions);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
<T extends ExtensionPoint> List<T> getAllExtensions(Class<T> extensionPoint) {
|
||||
Stream<T> pluginExtsStream = pluginManager.getExtensions(extensionPoint)
|
||||
|
|
|
@ -34,4 +34,13 @@ public interface ExtensionGetter {
|
|||
* the {@link ExtensionPointDefinition}.
|
||||
*/
|
||||
<T extends ExtensionPoint> Flux<T> getEnabledExtensionByDefinition(Class<T> extensionPoint);
|
||||
|
||||
/**
|
||||
* Get all extensions according to extension point class.
|
||||
*
|
||||
* @param extensionPointClass extension point class
|
||||
* @param <T> type of extension point
|
||||
* @return a bunch of extension points.
|
||||
*/
|
||||
<T extends ExtensionPoint> Flux<T> getExtensions(Class<T> extensionPointClass);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
package run.halo.app.security;
|
||||
|
||||
import static org.springframework.security.config.web.server.SecurityWebFiltersOrder.ANONYMOUS_AUTHENTICATION;
|
||||
import static org.springframework.security.config.web.server.SecurityWebFiltersOrder.AUTHENTICATION;
|
||||
import static org.springframework.security.config.web.server.SecurityWebFiltersOrder.FORM_LOGIN;
|
||||
|
||||
import lombok.Setter;
|
||||
import org.pf4j.ExtensionPoint;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.web.server.WebFilterChainProxy;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
import org.springframework.web.server.WebFilterChain;
|
||||
import reactor.core.publisher.Mono;
|
||||
import run.halo.app.plugin.extensionpoint.ExtensionGetter;
|
||||
import run.halo.app.security.authentication.SecurityConfigurer;
|
||||
|
||||
@Component
|
||||
public class SecurityWebFiltersConfigurer implements SecurityConfigurer {
|
||||
|
||||
private final ExtensionGetter extensionGetter;
|
||||
|
||||
public SecurityWebFiltersConfigurer(ExtensionGetter extensionGetter) {
|
||||
this.extensionGetter = extensionGetter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(ServerHttpSecurity http) {
|
||||
http
|
||||
.addFilterAt(
|
||||
new SecurityWebFilterChainProxy(FormLoginSecurityWebFilter.class), FORM_LOGIN
|
||||
)
|
||||
.addFilterAt(
|
||||
new SecurityWebFilterChainProxy(AuthenticationSecurityWebFilter.class),
|
||||
AUTHENTICATION
|
||||
)
|
||||
.addFilterAt(
|
||||
new SecurityWebFilterChainProxy(AnonymousAuthenticationSecurityWebFilter.class),
|
||||
ANONYMOUS_AUTHENTICATION
|
||||
);
|
||||
}
|
||||
|
||||
public class SecurityWebFilterChainProxy implements WebFilter {
|
||||
|
||||
@Setter
|
||||
private WebFilterChainProxy.WebFilterChainDecorator filterChainDecorator;
|
||||
|
||||
private final Class<? extends ExtensionPoint> extensionPointClass;
|
||||
|
||||
public SecurityWebFilterChainProxy(Class<? extends ExtensionPoint> extensionPointClass) {
|
||||
this.extensionPointClass = extensionPointClass;
|
||||
this.filterChainDecorator = new WebFilterChainProxy.DefaultWebFilterChainDecorator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||
return extensionGetter.getExtensions(this.extensionPointClass)
|
||||
.sort(AnnotationAwareOrderComparator.INSTANCE)
|
||||
.cast(WebFilter.class)
|
||||
.collectList()
|
||||
.map(filters -> filterChainDecorator.decorate(chain, filters))
|
||||
.flatMap(decoratedChain -> decoratedChain.filter(exchange));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
# Halo 认证扩展点
|
||||
|
||||
此前,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 留下机会。
|
||||
|
||||
后续会根据需求实现其他认证相关的扩展点。
|
Loading…
Reference in New Issue