1. 概述
上篇文章写了客户端连接时的验证,这篇文章写下对于客户端具体操作的权限控制,包括创建topic、发布消息和订阅消息等。
2. 客户端权限控制
2.1 修改broker.conf文件,打开权限控制
如果要开启对权限的控制,首先需要打开对连接的验证。
# Authorization provider fully qualified class-name
# 这个类需要我们自己实现,继承org.apache.pulsar.broker.authorization.AuthorizationProvider接口即可
authorizationProvider=auth.server.VVPulsarAuthorizationProvider
# Allow wildcard matching in authorization
# (wildcard matching only applicable if wildcard-char:
# * presents at first or last position eg: *.pulsar.service, pulsar.service.*)
authorizationAllowWildcardsMatching=false
# Role names that are treated as "super-user", meaning they will be able to do all admin
# operations and publish/consume from all topics
superUserRoles=vv-role,cc-role
2.2 实现AuthorizationProvider接口
下面只是给了一个demo,里面没有对客户端做任何控制。
package auth.server;
import org.apache.pulsar.broker.ServiceConfiguration;
import org.apache.pulsar.broker.authentication.AuthenticationDataSource;
import org.apache.pulsar.broker.authorization.AuthorizationProvider;
import org.apache.pulsar.broker.cache.ConfigurationCacheService;
import org.apache.pulsar.common.naming.NamespaceName;
import org.apache.pulsar.common.naming.TopicName;
import org.apache.pulsar.common.policies.data.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
/**
* @author cc
* @function
* @date 2021/7/27 14:38
*/
public class VVPulsarAuthorizationProvider implements AuthorizationProvider {
private static final Logger log = LoggerFactory.getLogger(VVPulsarAuthorizationProvider.class);
private static final String methodName = "vv_auth_v2";
@Override
public void initialize(ServiceConfiguration conf, ConfigurationCacheService configCache) throws IOException {
log.info(methodName + " initialize");
}
@Override
public CompletableFuture<Boolean> canProduceAsync(TopicName topicName, String role, AuthenticationDataSource authenticationData) {
return defaultResult("canProduceAsync", topicName, role);
}
@Override
public CompletableFuture<Boolean> canConsumeAsync(TopicName topicName, String role, AuthenticationDataSource authenticationData, String subscription) {
return defaultResult("canConsumeAsync", topicName, role);
}
@Override
public CompletableFuture<Boolean> canLookupAsync(TopicName topicName, String role, AuthenticationDataSource authenticationData) {
return defaultResult("canLookupAsync", topicName, role);
}
@Override
public CompletableFuture<Boolean> allowFunctionOpsAsync(NamespaceName namespaceName, String role, AuthenticationDataSource authenticationData) {
return defaultResult("allowFunctionOpsAsync", namespaceName, role);
}
@Override
public CompletableFuture<Boolean> allowSourceOpsAsync(NamespaceName namespaceName, String role, AuthenticationDataSource authenticationData) {
return defaultResult("allowSourceOpsAsync", namespaceName, role);
}
@Override
public CompletableFuture<Boolean> allowSinkOpsAsync(NamespaceName namespaceName, String role, AuthenticationDataSource authenticationData) {
return defaultResult("allowSinkOpsAsync", namespaceName, role);
}
@Override
public CompletableFuture<Void> grantPermissionAsync(NamespaceName namespace, Set<AuthAction> actions, String role, String authDataJson) {
return defaultVoidResult("grantPermissionAsync", namespace, role);
}
@Override
public CompletableFuture<Void> grantSubscriptionPermissionAsync(NamespaceName namespace, String subscriptionName, Set<String> roles, String authDataJson) {
return defaultVoidResult("grantSubscriptionPermissionAsync", namespace, roles.toString());
}
@Override
public CompletableFuture<Void> revokeSubscriptionPermissionAsync(NamespaceName namespace, String subscriptionName, String role, String authDataJson) {
return defaultVoidResult("revokeSubscriptionPermissionAsync", namespace, role);
}
@Override
public CompletableFuture<Void> grantPermissionAsync(TopicName topicName, Set<AuthAction> actions, String role, String authDataJson) {
return defaultVoidResult("grantPermissionAsync", topicName, role);
}
@Override
public void close() throws IOException {
log.info(methodName + " close");
}
@Override
public CompletableFuture<Boolean> allowTenantOperationAsync(String tenantName, String role, TenantOperation operation, AuthenticationDataSource authData) {
log.info(methodName + " " + tenantName + ", role " + role);
CompletableFuture<Boolean> permissionFuture = new CompletableFuture<>();
permissionFuture.complete(true);
return permissionFuture;
}
@Override
public CompletableFuture<Boolean> allowNamespaceOperationAsync(NamespaceName namespaceName, String role, NamespaceOperation operation, AuthenticationDataSource authData) {
return defaultResult("allowNamespaceOperationAsync", namespaceName, role);
}
@Override
public CompletableFuture<Boolean> allowNamespacePolicyOperationAsync(NamespaceName namespaceName, PolicyName policy, PolicyOperation operation, String role, AuthenticationDataSource authData) {
return defaultResult("allowNamespacePolicyOperationAsync", namespaceName, role);
}
@Override
public CompletableFuture<Boolean> allowTopicOperationAsync(TopicName topic, String role, TopicOperation operation, AuthenticationDataSource authData) {
return defaultResult("allowTopicOperationAsync", topic, role);
}
@Override
public CompletableFuture<Boolean> allowTopicPolicyOperationAsync(TopicName topic, String role, PolicyName policy, PolicyOperation operation, AuthenticationDataSource authData) {
return defaultResult("allowTopicPolicyOperationAsync", topic, role);
}
CompletableFuture<Boolean> defaultResult(String name, TopicName topicName, String role) {
log.info(methodName + " " + name + ", topicName " + topicName.toString() + ", role " + role);
CompletableFuture<Boolean> permissionFuture = new CompletableFuture<>();
permissionFuture.complete(true);
return permissionFuture;
}
CompletableFuture<Boolean> defaultResult(String name, NamespaceName namespaceName, String role) {
log.info(methodName + " " + name + ", topicName " + namespaceName.toString() + ", role " + role);
CompletableFuture<Boolean> permissionFuture = new CompletableFuture<>();
permissionFuture.complete(true);
return permissionFuture;
}
CompletableFuture<Void> defaultVoidResult(String name, TopicName topicName, String role) {
log.info(methodName + " " + name + ", topicName " + topicName.toString() + ", role " + role);
CompletableFuture<Void> permissionFuture = new CompletableFuture<>();
permissionFuture.complete(null);
return permissionFuture;
}
CompletableFuture<Void> defaultVoidResult(String name, NamespaceName namespaceName, String role) {
log.info(methodName + " " + name + ", topicName " + namespaceName.toString() + ", role " + role);
CompletableFuture<Void> permissionFuture = new CompletableFuture<>();
permissionFuture.complete(null);
return permissionFuture;
}
}
3 理解权限控制
在pulsar中,权限是在role的层次上进行控制的。在客户端连接的验证过程中,会保存客户端的role,然后在上述接口中可以结合role和具体操作进行限制。
此处的role其实是VVAuthenticationProvider中返回的,而这个数据是客户端连接认证阶段客户端携带过去的。
所以,可以设置一个认证中心,统一管理所有的用户权限。客户端连接后去认证中心获取自己的用户信息,携带用户信息连接到broker,然后broker根据用户信息去认证中心获取连接权限和其他操作权限,从而实现对用户的权限控制。