refactor: restrict author page access to users with post permission (#7279)

#### What type of PR is this?
/kind improvement
/area core
/milestone 2.20.x

#### What this PR does / why we need it:
仅对包含文章权限的用户生成作者页面

#### Which issue(s) this PR fixes:

Fixes #7202

#### Does this PR introduce a user-facing change?

```release-note
仅对包含文章权限的用户生成作者页面
```
pull/7282/head
guqing 2025-03-10 12:37:01 +08:00 committed by GitHub
parent 5c2c298bc3
commit 2c4c876ef2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 35 additions and 8 deletions

View File

@ -26,6 +26,8 @@ public enum AuthorityUtils {
public static final String COMMENT_MANAGEMENT_ROLE_NAME = "role-template-manage-comments";
public static final String POST_CONTRIBUTOR_ROLE_NAME = "role-template-post-contributor";
/**
* Converts an array of GrantedAuthority objects to a role set.
*

View File

@ -5,6 +5,7 @@ import static org.springframework.web.reactive.function.server.RequestPredicates
import static run.halo.app.theme.router.PageUrlUtils.totalPage;
import java.util.Map;
import java.util.Set;
import lombok.AllArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
@ -16,10 +17,12 @@ import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.i18n.LocaleContextResolver;
import reactor.core.publisher.Mono;
import run.halo.app.core.extension.User;
import run.halo.app.core.user.service.RoleService;
import run.halo.app.extension.ReactiveExtensionClient;
import run.halo.app.infra.SystemConfigurableEnvironmentFetcher;
import run.halo.app.infra.SystemSetting;
import run.halo.app.infra.exception.NotFoundException;
import run.halo.app.security.authorization.AuthorityUtils;
import run.halo.app.theme.DefaultTemplateEnum;
import run.halo.app.theme.finders.PostFinder;
import run.halo.app.theme.finders.vo.ListedPostVo;
@ -42,6 +45,7 @@ public class AuthorPostsRouteFactory implements RouteFactory {
private final PostFinder postFinder;
private final ReactiveExtensionClient client;
private final RoleService roleService;
private SystemConfigurableEnvironmentFetcher environmentFetcher;
private final TitleVisibilityIdentifyCalculator titleVisibilityIdentifyCalculator;
@ -58,16 +62,31 @@ public class AuthorPostsRouteFactory implements RouteFactory {
HandlerFunction<ServerResponse> handlerFunction() {
return request -> {
String name = request.pathVariable("name");
return ServerResponse.ok()
.render(DefaultTemplateEnum.AUTHOR.getValue(),
Map.of("author", getByName(name),
"posts", postList(request, name),
ModelConst.TEMPLATE_ID, DefaultTemplateEnum.AUTHOR.getValue()
)
);
return hasPostManageRole(name)
.flatMap(hasPostManageRole -> {
if (hasPostManageRole) {
return ServerResponse.ok()
.render(DefaultTemplateEnum.AUTHOR.getValue(),
Map.of("author", getByName(name),
"posts", postList(request, name),
ModelConst.TEMPLATE_ID, DefaultTemplateEnum.AUTHOR.getValue()
)
);
}
return Mono.error(new NotFoundException("Author page not found."));
});
};
}
protected Mono<Boolean> hasPostManageRole(String username) {
return roleService.getRolesByUsername(username)
.collectList()
.flatMap(roles -> roleService.contains(roles,
Set.of(AuthorityUtils.POST_CONTRIBUTOR_ROLE_NAME))
)
.defaultIfEmpty(false);
}
private Mono<UrlContextListResult<ListedPostVo>> postList(ServerRequest request, String name) {
String path = request.path();
int pageNum = pageNumInPathVariable(request);

View File

@ -1,6 +1,9 @@
package run.halo.app.theme.router.factories;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.Test;
@ -30,7 +33,10 @@ class AuthorPostsRouteFactoryTest extends RouteFactoryTestSuite {
@Test
void create() {
RouterFunction<ServerResponse> routerFunction = authorPostsRouteFactory.create(null);
var spyAuthorRoute = spy(authorPostsRouteFactory);
doReturn(Mono.just(true)).when(spyAuthorRoute).hasPostManageRole(anyString());
RouterFunction<ServerResponse> routerFunction = spyAuthorRoute.create(null);
WebTestClient webClient = getWebTestClient(routerFunction);
when(client.fetch(eq(User.class), eq("fake-user")))