mirror of
https://github.com/didi/KnowStreaming.git
synced 2025-12-24 11:52:08 +08:00
merge master
This commit is contained in:
11
README.md
11
README.md
@@ -67,11 +67,16 @@
|
|||||||
- [滴滴Logi-KafkaManager 系列视频教程](https://mp.weixin.qq.com/s/9X7gH0tptHPtfjPPSdGO8g)
|
- [滴滴Logi-KafkaManager 系列视频教程](https://mp.weixin.qq.com/s/9X7gH0tptHPtfjPPSdGO8g)
|
||||||
- [kafka实践(十五):滴滴开源Kafka管控平台 Logi-KafkaManager研究--A叶子叶来](https://blog.csdn.net/yezonggang/article/details/113106244)
|
- [kafka实践(十五):滴滴开源Kafka管控平台 Logi-KafkaManager研究--A叶子叶来](https://blog.csdn.net/yezonggang/article/details/113106244)
|
||||||
|
|
||||||
## 3 滴滴Logi开源用户钉钉交流群
|
## 3 滴滴Logi开源用户交流群
|
||||||
|
|
||||||
|
|
||||||
|

|
||||||
|
微信加群:关注公众号 Obsuite(官方公众号) 回复 "Logi加群"
|
||||||
|
|
||||||

|

|
||||||
钉钉群ID:32821440
|
钉钉群ID:32821440
|
||||||
|
|
||||||
|
|
||||||
## 4 OCE认证
|
## 4 OCE认证
|
||||||
OCE是一个认证机制和交流平台,为滴滴Logi-KafkaManager生产用户量身打造,我们会为OCE企业提供更好的技术支持,比如专属的技术沙龙、企业一对一的交流机会、专属的答疑群等,如果贵司Logi-KafkaManager上了生产,[快来加入吧](http://obsuite.didiyun.com/open/openAuth)
|
OCE是一个认证机制和交流平台,为滴滴Logi-KafkaManager生产用户量身打造,我们会为OCE企业提供更好的技术支持,比如专属的技术沙龙、企业一对一的交流机会、专属的答疑群等,如果贵司Logi-KafkaManager上了生产,[快来加入吧](http://obsuite.didiyun.com/open/openAuth)
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# FAQ
|
# FAQ
|
||||||
|
|
||||||
- 0、支持哪些Kafka版本?
|
- 0、支持哪些Kafka版本?
|
||||||
- 1、Topic申请、新建监控告警等操作时没有可选择的集群?
|
- 1、Topic申请、新建监控告警等操作时没有可选择的集群?
|
||||||
@@ -17,9 +17,11 @@
|
|||||||
- 5、如何对接夜莺的监控告警功能?
|
- 5、如何对接夜莺的监控告警功能?
|
||||||
- 6、如何使用`MySQL 8`?
|
- 6、如何使用`MySQL 8`?
|
||||||
- 7、`Jmx`连接失败如何解决?
|
- 7、`Jmx`连接失败如何解决?
|
||||||
- 8、`topic biz data not exist`错误及处理方式?
|
- 8、`topic biz data not exist`错误及处理方式
|
||||||
- 9、进程启动后,如何查看API文档?
|
- 9、进程启动后,如何查看API文档
|
||||||
- 10、集群申请审批通过之后,为什么还是看不到集群?
|
- 10、如何创建告警组?
|
||||||
|
- 11、连接信息、耗时信息为什么没有数据?
|
||||||
|
- 12、逻辑集群申请审批通过之后为什么看不到逻辑集群?
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -35,7 +37,7 @@
|
|||||||
|
|
||||||
逻辑集群的创建参看:
|
逻辑集群的创建参看:
|
||||||
|
|
||||||
- [kafka-manager 接入集群](docs/user_guide/add_cluster/add_cluster.md) 手册,这里的Region和逻辑集群都必须添加。
|
- [kafka-manager 接入集群](add_cluster/add_cluster.md) 手册,这里的Region和逻辑集群都必须添加。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -106,14 +108,21 @@
|
|||||||
|
|
||||||
### 9、进程启动后,如何查看API文档
|
### 9、进程启动后,如何查看API文档
|
||||||
|
|
||||||
- 滴滴Logi-KafkaManager采用Swagger-API工具记录API文档。Swagger-API地址: [http://IP:PORT/swagger-ui.html#/](http://IP:PORT/swagger-ui.html#/)
|
- 滴滴Logi-KafkaManager采用Swagger-API工具记录API文档。Swagger-API地址: [http://IP:PORT/swagger-ui.html#/](http://IP:PORT/swagger-ui.html#/)
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 10、集群申请审批通过之后,为什么还是看不到集群?
|
### 10、如何创建告警组?
|
||||||
|
|
||||||
集群申请,审批通过,那块的通过只是将工单的状态修改为通过。实际集群的分配搭建等,还需要运维去手动操作。
|
这块需要配合监控系统进行使用,现在默认已经实现了夜莺的对接,当然也可以对接自己内部的监控系统,不过需要实现一些接口。
|
||||||
|
|
||||||
Logi-KM整体设计上,用户侧看到的是逻辑集群,管控侧看到的是物理集群,因此这里的手动操作,是需要创建一个逻辑集群。
|
具体的文档可见:[监控功能对接夜莺](../dev_guide/monitor_system_integrate_with_n9e.md)、[监控功能对接其他系统](../dev_guide/monitor_system_integrate_with_self.md)
|
||||||
|
|
||||||
逻辑集群的创建,具体可以看README里面的用户文档。
|
### 11、连接信息、耗时信息为什么没有数据?
|
||||||
|
|
||||||
|
这块需要结合滴滴内部的kafka-gateway一同使用才会有数据,滴滴kafka-gateway暂未开源。
|
||||||
|
|
||||||
|
### 12、逻辑集群申请审批通过之后为什么看不到逻辑集群?
|
||||||
|
|
||||||
|
逻辑集群的申请与审批仅仅只是一个工单流程,并不会去实际创建逻辑集群,逻辑集群的创建还需要手动去创建。
|
||||||
|
|
||||||
|
具体的操作可见:[kafka-manager 接入集群](add_cluster/add_cluster.md)。
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ public enum ResultStatus {
|
|||||||
STORAGE_UPLOAD_FILE_FAILED(8050, "upload file failed"),
|
STORAGE_UPLOAD_FILE_FAILED(8050, "upload file failed"),
|
||||||
STORAGE_FILE_TYPE_NOT_SUPPORT(8051, "File type not support"),
|
STORAGE_FILE_TYPE_NOT_SUPPORT(8051, "File type not support"),
|
||||||
STORAGE_DOWNLOAD_FILE_FAILED(8052, "download file failed"),
|
STORAGE_DOWNLOAD_FILE_FAILED(8052, "download file failed"),
|
||||||
LDAP_AUTHENTICATION_FAILED(8053, "LDAP authentication failed"),
|
LDAP_AUTHENTICATION_FAILED(8053, "ldap authentication failed"),
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mobx-ts-example",
|
"name": "logi-kafka",
|
||||||
"version": "1.0.0",
|
"version": "2.3.1",
|
||||||
"description": "",
|
"description": "",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "webpack-dev-server",
|
"start": "webpack-dev-server",
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
"@types/spark-md5": "^3.0.2",
|
"@types/spark-md5": "^3.0.2",
|
||||||
"antd": "^3.26.15",
|
"antd": "^3.26.15",
|
||||||
"clean-webpack-plugin": "^3.0.0",
|
"clean-webpack-plugin": "^3.0.0",
|
||||||
"clipboard": "^2.0.6",
|
"clipboard": "2.0.6",
|
||||||
"cross-env": "^7.0.2",
|
"cross-env": "^7.0.2",
|
||||||
"css-loader": "^2.1.0",
|
"css-loader": "^2.1.0",
|
||||||
"echarts": "^4.5.0",
|
"echarts": "^4.5.0",
|
||||||
@@ -56,4 +56,4 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"format-to-json": "^1.0.4"
|
"format-to-json": "^1.0.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.xiaojukeji.kafka.manager.common.utils.ldap;
|
package com.xiaojukeji.kafka.manager.account.component.ldap;
|
||||||
|
|
||||||
import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils;
|
import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@@ -15,33 +17,31 @@ import javax.naming.ldap.LdapContext;
|
|||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class LDAPAuthentication {
|
public class LdapAuthentication {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(LdapAuthentication.class);
|
||||||
|
|
||||||
@Value(value = "${ldap.url}")
|
@Value(value = "${account.ldap.url:}")
|
||||||
private String ldapUrl;
|
private String ldapUrl;
|
||||||
|
|
||||||
@Value(value = "${ldap.basedn}")
|
@Value(value = "${account.ldap.basedn:}")
|
||||||
private String ldapBasedn;
|
private String ldapBasedn;
|
||||||
|
|
||||||
@Value(value = "${ldap.factory}")
|
@Value(value = "${account.ldap.factory:}")
|
||||||
private String ldapFactory;
|
private String ldapFactory;
|
||||||
|
|
||||||
@Value(value = "${ldap.filter}")
|
@Value(value = "${account.ldap.filter:}")
|
||||||
private String ldapfilter;
|
private String ldapFilter;
|
||||||
|
|
||||||
@Value(value = "${ldap.auth-user-registration-role}")
|
@Value(value = "${account.ldap.security.authentication:}")
|
||||||
private String authUserRegistrationRole;
|
|
||||||
|
|
||||||
@Value(value = "${ldap.security.authentication}")
|
|
||||||
private String securityAuthentication;
|
private String securityAuthentication;
|
||||||
|
|
||||||
@Value(value = "${ldap.security.principal}")
|
@Value(value = "${account.ldap.security.principal:}")
|
||||||
private String securityPrincipal;
|
private String securityPrincipal;
|
||||||
|
|
||||||
@Value(value = "${ldap.security.credentials}")
|
@Value(value = "${account.ldap.security.credentials:}")
|
||||||
private String securityCredentials;
|
private String securityCredentials;
|
||||||
|
|
||||||
private LdapContext getConnect() {
|
private LdapContext getLdapContext() {
|
||||||
Hashtable<String, String> env = new Hashtable<String, String>();
|
Hashtable<String, String> env = new Hashtable<String, String>();
|
||||||
env.put(Context.INITIAL_CONTEXT_FACTORY, ldapFactory);
|
env.put(Context.INITIAL_CONTEXT_FACTORY, ldapFactory);
|
||||||
env.put(Context.PROVIDER_URL, ldapUrl + ldapBasedn);
|
env.put(Context.PROVIDER_URL, ldapUrl + ldapBasedn);
|
||||||
@@ -53,19 +53,19 @@ public class LDAPAuthentication {
|
|||||||
try {
|
try {
|
||||||
return new InitialLdapContext(env, null);
|
return new InitialLdapContext(env, null);
|
||||||
} catch (AuthenticationException e) {
|
} catch (AuthenticationException e) {
|
||||||
e.printStackTrace();
|
LOGGER.warn("class=LdapAuthentication||method=getLdapContext||errMsg={}", e);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
LOGGER.error("class=LdapAuthentication||method=getLdapContext||errMsg={}", e);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getUserDN(String account,LdapContext ctx) {
|
private String getUserDN(String account, LdapContext ctx) {
|
||||||
String userDN = "";
|
String userDN = "";
|
||||||
try {
|
try {
|
||||||
SearchControls constraints = new SearchControls();
|
SearchControls constraints = new SearchControls();
|
||||||
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
|
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
|
||||||
String filter = "(&(objectClass=*)("+ldapfilter+"=" + account + "))";
|
String filter = "(&(objectClass=*)("+ldapFilter+"=" + account + "))";
|
||||||
|
|
||||||
NamingEnumeration<SearchResult> en = ctx.search("", filter, constraints);
|
NamingEnumeration<SearchResult> en = ctx.search("", filter, constraints);
|
||||||
if (en == null || !en.hasMoreElements()) {
|
if (en == null || !en.hasMoreElements()) {
|
||||||
@@ -82,9 +82,8 @@ public class LDAPAuthentication {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
LOGGER.error("class=LdapAuthentication||method=getUserDN||account={}||errMsg={}", account, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return userDN;
|
return userDN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,35 +93,38 @@ public class LDAPAuthentication {
|
|||||||
* @param password
|
* @param password
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean authenricate(String account, String password) {
|
public boolean authenticate(String account, String password) {
|
||||||
LdapContext ctx = getConnect();
|
LdapContext ctx = getLdapContext();
|
||||||
|
if (ValidateUtils.isNull(ctx)) {
|
||||||
boolean valide = false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String userDN = getUserDN(account,ctx);
|
String userDN = getUserDN(account, ctx);
|
||||||
if(ValidateUtils.isBlank(userDN)){
|
if(ValidateUtils.isBlank(userDN)){
|
||||||
return valide;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, userDN);
|
ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, userDN);
|
||||||
ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, password);
|
ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, password);
|
||||||
ctx.reconnect(null);
|
ctx.reconnect(null);
|
||||||
valide = true;
|
|
||||||
} catch (AuthenticationException e) {
|
return true;
|
||||||
System.out.println(e.toString());
|
} catch (AuthenticationException e) {
|
||||||
|
LOGGER.warn("class=LdapAuthentication||method=authenticate||account={}||errMsg={}", account, e);
|
||||||
} catch (NamingException e) {
|
} catch (NamingException e) {
|
||||||
e.printStackTrace();
|
LOGGER.warn("class=LdapAuthentication||method=authenticate||account={}||errMsg={}", account, e);
|
||||||
}finally {
|
} catch (Exception e) {
|
||||||
if(ctx!=null) {
|
LOGGER.error("class=LdapAuthentication||method=authenticate||account={}||errMsg={}", account, e);
|
||||||
|
} finally {
|
||||||
|
if(ctx != null) {
|
||||||
try {
|
try {
|
||||||
ctx.close();
|
ctx.close();
|
||||||
} catch (NamingException e) {
|
} catch (NamingException e) {
|
||||||
e.printStackTrace();
|
LOGGER.error("class=LdapAuthentication||method=authenticate||account={}||errMsg={}", account, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
return valide;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ import com.xiaojukeji.kafka.manager.common.entity.dto.normal.LoginDTO;
|
|||||||
import com.xiaojukeji.kafka.manager.common.entity.pojo.AccountDO;
|
import com.xiaojukeji.kafka.manager.common.entity.pojo.AccountDO;
|
||||||
import com.xiaojukeji.kafka.manager.common.utils.EncryptUtil;
|
import com.xiaojukeji.kafka.manager.common.utils.EncryptUtil;
|
||||||
import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils;
|
import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils;
|
||||||
import com.xiaojukeji.kafka.manager.common.utils.ldap.LDAPAuthentication;
|
import com.xiaojukeji.kafka.manager.account.component.ldap.LdapAuthentication;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -28,18 +28,18 @@ public class BaseSessionSignOn extends AbstractSingleSignOn {
|
|||||||
private AccountService accountService;
|
private AccountService accountService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private LDAPAuthentication ldapAuthentication;
|
private LdapAuthentication ldapAuthentication;
|
||||||
|
|
||||||
//是否开启ldap验证
|
//是否开启ldap验证
|
||||||
@Value(value = "${ldap.enabled}")
|
@Value(value = "${account.ldap.enabled:}")
|
||||||
private boolean ldapEnabled;
|
private Boolean accountLdapEnabled;
|
||||||
|
|
||||||
//ldap自动注册的默认角色。请注意:它通常来说都是低权限角色
|
//ldap自动注册的默认角色。请注意:它通常来说都是低权限角色
|
||||||
@Value(value = "${ldap.auth-user-registration-role}")
|
@Value(value = "${account.ldap.auth-user-registration-role:}")
|
||||||
private String authUserRegistrationRole;
|
private String authUserRegistrationRole;
|
||||||
|
|
||||||
//ldap自动注册是否开启
|
//ldap自动注册是否开启
|
||||||
@Value(value = "${ldap.auth-user-registration}")
|
@Value(value = "${account.ldap.auth-user-registration:}")
|
||||||
private boolean authUserRegistration;
|
private boolean authUserRegistration;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -50,11 +50,10 @@ public class BaseSessionSignOn extends AbstractSingleSignOn {
|
|||||||
|
|
||||||
Result<AccountDO> accountResult = accountService.getAccountDO(dto.getUsername());
|
Result<AccountDO> accountResult = accountService.getAccountDO(dto.getUsername());
|
||||||
|
|
||||||
//modifier limin
|
//判断是否激活了LDAP验证, 若激活则也可使用ldap进行认证
|
||||||
//判断是否激活了LDAP验证。若激活并且数据库无此用户则自动注册
|
if(!ValidateUtils.isNull(accountLdapEnabled) && accountLdapEnabled){
|
||||||
if(ldapEnabled){
|
|
||||||
//去LDAP验证账密
|
//去LDAP验证账密
|
||||||
if(!ldapAuthentication.authenricate(dto.getUsername(),dto.getPassword())){
|
if(!ldapAuthentication.authenticate(dto.getUsername(),dto.getPassword())){
|
||||||
return Result.buildFrom(ResultStatus.LDAP_AUTHENTICATION_FAILED);
|
return Result.buildFrom(ResultStatus.LDAP_AUTHENTICATION_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,14 +62,13 @@ public class BaseSessionSignOn extends AbstractSingleSignOn {
|
|||||||
AccountDO accountDO = new AccountDO();
|
AccountDO accountDO = new AccountDO();
|
||||||
accountDO.setUsername(dto.getUsername());
|
accountDO.setUsername(dto.getUsername());
|
||||||
accountDO.setRole(AccountRoleEnum.getUserRoleEnum(authUserRegistrationRole).getRole());
|
accountDO.setRole(AccountRoleEnum.getUserRoleEnum(authUserRegistrationRole).getRole());
|
||||||
accountDO.setPassword(EncryptUtil.md5(dto.getPassword()));
|
accountDO.setPassword(dto.getPassword());
|
||||||
accountService.createAccount(accountDO);
|
accountService.createAccount(accountDO);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.buildSuc(dto.getUsername());
|
return Result.buildSuc(dto.getUsername());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ValidateUtils.isNull(accountResult) || accountResult.failed()) {
|
if (ValidateUtils.isNull(accountResult) || accountResult.failed()) {
|
||||||
return new Result<>(accountResult.getCode(), accountResult.getMessage());
|
return new Result<>(accountResult.getCode(), accountResult.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ spring:
|
|||||||
name: kafkamanager
|
name: kafkamanager
|
||||||
datasource:
|
datasource:
|
||||||
kafka-manager:
|
kafka-manager:
|
||||||
|
|
||||||
jdbc-url: jdbc:mysql://127.0.0.1:3306/logi_kafka_manager?characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
|
jdbc-url: jdbc:mysql://127.0.0.1:3306/logi_kafka_manager?characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
|
||||||
username: admin
|
username: admin
|
||||||
password: admin
|
password: admin
|
||||||
@@ -50,6 +49,17 @@ task:
|
|||||||
|
|
||||||
account:
|
account:
|
||||||
ldap:
|
ldap:
|
||||||
|
enabled: false
|
||||||
|
url: ldap://127.0.0.1:389/
|
||||||
|
basedn: dc=tsign,dc=cn
|
||||||
|
factory: com.sun.jndi.ldap.LdapCtxFactory
|
||||||
|
filter: sAMAccountName
|
||||||
|
security:
|
||||||
|
authentication: simple
|
||||||
|
principal: cn=admin,dc=tsign,dc=cn
|
||||||
|
credentials: admin
|
||||||
|
auth-user-registration: true
|
||||||
|
auth-user-registration-role: normal
|
||||||
|
|
||||||
kcm:
|
kcm:
|
||||||
enabled: false
|
enabled: false
|
||||||
@@ -83,16 +93,3 @@ notify:
|
|||||||
topic-name: didi-kafka-notify
|
topic-name: didi-kafka-notify
|
||||||
order:
|
order:
|
||||||
detail-url: http://127.0.0.1
|
detail-url: http://127.0.0.1
|
||||||
|
|
||||||
ldap:
|
|
||||||
enabled: false
|
|
||||||
url: ldap://127.0.0.1:389/
|
|
||||||
basedn: dc=tsign,dc=cn
|
|
||||||
factory: com.sun.jndi.ldap.LdapCtxFactory
|
|
||||||
filter: sAMAccountName
|
|
||||||
security:
|
|
||||||
authentication: simple
|
|
||||||
principal: cn=admin,dc=tsign,dc=cn
|
|
||||||
credentials: admin
|
|
||||||
auth-user-registration-role: normal
|
|
||||||
auth-user-registration: true
|
|
||||||
|
|||||||
Reference in New Issue
Block a user