dubbo設置連接zookeeper權限

  1. 前言

         最近自己的技術棧項目, 再升級dubbo爲2.7.5,  zookeeper爲3.5.6, curator-recipes升級爲4.2.0的時候一直出現zookeeper   not connected和Connection lost for ***的錯誤。之前未升級前還是好的...隨手查看報錯源碼信息並百度,終於再stackflow上面找到原因.設置環境參數ZKClientConfig.ENABLE_CLIENT_SASL_KEY=false,默認未true

System.setProperty(ZKClientConfig.ENABLE_CLIENT_SASL_KEY, Constant.IS_FALSE.toString());

         大概意思是zookeeper作爲外部應用需要向系統申請資源,申請資源的時候需要通過認證,而sasl是一種認證方式,添加以上那一句來繞過sasl認證。避免等待,來提高效率。         

         隨後繼續深進,瞭解到zookeeper的sasl認證相關(試了下, 效果不大好, 可能我姿勢不大對? 這裏就不介紹zk的sasl介紹和相關配置了, 有興趣的可以自行百度),  並附加的深入學習了zk的ACL 權限, 以及dubbo以zk未註冊中心的,權限認證!  下面開始相關介紹。

  1. zookeeper設置ACL 權限

查閱dubbo的官方文檔dubbo-registry發現連接註冊中心的時候是可以選擇是否需要用戶名密碼,接下來就是要如何設置zookeeper的用戶名跟密碼

clipboard.png

進入zookeeper的bin文件夾運行客戶端

./zkCli.sh

help 查看指令

[zk: localhost:2181(CONNECTED) 0] help
ZooKeeper -server host:port cmd args
    stat path [watch]
    set path data [version]
    ls path [watch]
    delquota [-n|-b] path
    ls2 path [watch]
    setAcl path acl
    setquota -n|-b val path
    history 
    redo cmdno
    printwatches on|off
    delete path [version]
    sync path
    listquota path
    rmr path
    get path [watch]
    create [-s] [-e] path data acl
    addauth scheme auth
    quit 
    getAcl path
    close 
    connect host:port

如果在dubbo中沒有指定分組的話,dubbo會默認生成一個分組dubbo,也就是在zookeeper下面會有個子節點dubbo

也可以自己手動創建

create /dubbo

Zookeeper的ACL通過scheme:username:password:permissions來構成權限
scheme這邊主要用到2種方式,另外還有設置ip和host,這幾個沒用到的這邊就先不細說

1.auth方式(密碼明文)
添加用戶名和密碼

addauth digest admin:13871500871

授予/dubbo auth權限

setAcl /dubbo auth:admin:13871500871:rwadc

配置dubbo連接zookeeper配置文件

<dubbo:registry protocol ="zookeeper" address="127.0.0.1:2181"  username="admin" password="13871500871" client="curator" />

2.digest授權方式(方式跟auth差不多)
授予/dubbo digest權限

addauth digest admin:jI+oJfxCaWyh/3Zw/r+fwhbZVRY=
setAcl /dubbo digest:admin:jI+oJfxCaWyh/3Zw/r+fwhbZVRY=:cdrwa

配置zookeeper配置文件

<dubbo:registry protocol ="zookeeper" address="127.0.0.1:2181"  username="admin" password="13871500871" client="curator" />

digest 密碼生成方式:把密碼進行sha1編碼然後對結果進行base64編碼

BASE64(SHA1(password))

查看zookeeper源碼發現,其實包裏面已經有現成的方法,直接調用這個類生成就行,
idPassword字符串格式: username:password
org.apache.zookeeper.server.auth.DigestAuthenticationProvider

static public String generateDigest(String idPassword) throws NoSuchAlgorithmException {
        String parts[] = idPassword.split(":", 2);
        byte digest[] = MessageDigest.getInstance("SHA1").digest(
                idPassword.getBytes());
        return parts[0] + ":" + base64Encode(digest);
}

還有一個點就是要設置client="curator"
通過ZookeeperRegistry發現zookeeper的連接是通過zookeeperTransporter進行創建,
zookeeperTransporter接口分別由CuratorZookeeperTransporterZkclientZookeeperTransporter實現,這2個分別創建
CuratorZookeeperClient和ZkclientZookeeperClient

public class ZkclientZookeeperTransporter implements ZookeeperTransporter {
    public ZookeeperClient connect(URL url) {
        return new ZkclientZookeeperClient(url);
    }
}
public class CuratorZookeeperTransporter implements ZookeeperTransporter {
    public ZookeeperClient connect(URL url) {
        return new CuratorZookeeperClient(url);
    }
}

查看源碼發現ZkclientZookeeperClient是沒有進行設置zookeeper的auth的賬號和密碼,
CuratorZookeeperClient有去獲取配置的相關用戶信息。

    public ZkclientZookeeperClient(URL url) {
        super(url);
        client = new ZkClient(url.getBackupAddress());
        client.subscribeStateChanges(new IZkStateListener() {
            public void handleStateChanged(KeeperState state) throws Exception {
                ZkclientZookeeperClient.this.state = state;
                if (state == KeeperState.Disconnected) {
                    stateChanged(StateListener.DISCONNECTED);
                } else if (state == KeeperState.SyncConnected) {
                    stateChanged(StateListener.CONNECTED);
                }
            }
            public void handleNewSession() throws Exception {
                stateChanged(StateListener.RECONNECTED);
            }
        });
    }
    public CuratorZookeeperClient(URL url) {
        super(url);
        try {
            Builder builder = CuratorFrameworkFactory.builder()
                    .connectString(url.getBackupAddress())
                    .retryPolicy(new RetryNTimes(Integer.MAX_VALUE, 1000))  
                    .connectionTimeoutMs(5000);
            String authority = url.getAuthority();
            if (authority != null && authority.length() > 0) {
                builder = builder.authorization("digest", authority.getBytes());
            }
            client = builder.build();
            client.getConnectionStateListenable().addListener(new ConnectionStateListener() {
                public void stateChanged(CuratorFramework client, ConnectionState state) {
                    if (state == ConnectionState.LOST) {
                        CuratorZookeeperClient.this.stateChanged(StateListener.DISCONNECTED);
                    } else if (state == ConnectionState.CONNECTED) {
                        CuratorZookeeperClient.this.stateChanged(StateListener.CONNECTED);
                    } else if (state == ConnectionState.RECONNECTED) {
                        CuratorZookeeperClient.this.stateChanged(StateListener.RECONNECTED);
                    }
                }
            });
            client.start();
        } catch (IOException e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

cdrwa表示zookeeper的五種權限

CREATE: 創建子節點
READ: 獲取節點數據或者當前節點的子節點列表
WRITE: 節點設置數據
DELETE: 刪除子節點
ADMIN: 節點設置權限

如果用戶名密碼錯誤,或者沒設置,會報KeeperErrorCode = NoAuth錯誤

注:停止zookeeper,清除zookeeper文件夾下面的logs,或者用delete 刪除節點 就可以清除權限

發佈了102 篇原創文章 · 獲贊 220 · 訪問量 37萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章