從零開始實現 mq-13-註冊鑑權 auth

語言: CN / TW / HK

註冊鑑權

我們前面實現了 mq 的基本功能,不過還是存在一個問題,那就是 mq 沒有進行鑑權。

這就會導致如果部署在公網,任何一個機器都可以連線我們的服務,這顯然是不夠安全的。

生產者實現

屬性

生產者啟動時新增 2 個屬性:

/**
 * 賬戶標識
 * @since 0.1.4
 */
private String appKey;

/**
 * 賬戶密碼
 * @since 0.1.4
 */
private String appSecret;

註冊邏輯調整

註冊時,新增這兩個屬性到服務端。

public void registerToBroker() {
    int successCount = 0;
    for(RpcChannelFuture channelFuture : this.channelFutureList) {
        ServiceEntry serviceEntry = new ServiceEntry();
        serviceEntry.setGroupName(groupName);
        serviceEntry.setAddress(channelFuture.getAddress());
        serviceEntry.setPort(channelFuture.getPort());
        serviceEntry.setWeight(channelFuture.getWeight());

        BrokerRegisterReq brokerRegisterReq = new BrokerRegisterReq();
        brokerRegisterReq.setServiceEntry(serviceEntry);
        brokerRegisterReq.setMethodType(MethodType.P_REGISTER);
        brokerRegisterReq.setTraceId(IdHelper.uuid32());
        brokerRegisterReq.setAppKey(appKey);
        brokerRegisterReq.setAppSecret(appSecret);
        log.info("[Register] 開始註冊到 broker:{}", JSON.toJSON(brokerRegisterReq));
        final Channel channel = channelFuture.getChannelFuture().channel();
        MqCommonResp resp = callServer(channel, brokerRegisterReq, MqCommonResp.class);
        log.info("[Register] 完成註冊到 broker:{}", JSON.toJSON(resp));
        if(MqCommonRespCode.SUCCESS.getCode().equals(resp.getRespCode())) {
            successCount++;
        }
    }
    if(successCount <= 0 && check) {
        log.error("校驗 broker 可用性,可連線成功數為 0");
        throw new MqException(MqCommonRespCode.P_REGISTER_TO_BROKER_FAILED);
    }
}

消費者

消費者連線到 broker 也是類似的,此處不做贅述。

Broker 的處理

註冊邏輯

以前註冊是直接成功,此處加一個業務判斷。

// 生產者註冊
if(MethodType.P_REGISTER.equals(methodType)) {
    BrokerRegisterReq registerReq = JSON.parseObject(json, BrokerRegisterReq.class);
    if(!brokerRegisterValidService.producerValid(registerReq)) {
        log.error("{} 生產者註冊驗證失敗", JSON.toJSON(registerReq));
        throw new MqException(MqBrokerRespCode.P_REGISTER_VALID_FAILED);
    }

    return registerProducerService.register(registerReq.getServiceEntry(), channel);
}

首先會校驗有效性,這個是一個介面,可自行靈活替換。

其他業務邏輯

其他業務處理時,都需要 registerProducerService.checkValid(channelId); 進行有效性判斷。

// 生產者登出
if(MethodType.P_UN_REGISTER.equals(methodType)) {
    registerProducerService.checkValid(channelId);

    BrokerRegisterReq registerReq = JSON.parseObject(json, BrokerRegisterReq.class);
    return registerProducerService.unRegister(registerReq.getServiceEntry(), channel);
}

小結

註冊鑑權實現的原理非常簡單,不過可以為安全性提供最基礎的保障。

希望本文對你有所幫助,如果喜歡,歡迎點贊收藏轉發一波。

我是老馬,期待與你的下次重逢。

開源地址