You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

仅用公开用户ID在Telegram发消息(无需Access Hash)的实现方案

Telegram用户客户端发送消息:仅知公开ID时的解决方案

背景

以普通用户账户(非机器人)开发Telegram集成功能,需向仅知道公开数字用户ID的用户发送消息,但MTProto协议通常要求同时提供用户ID和access hash,现有代码在未缓存access hash时执行失败。


具体疑问与解答

1. 是否存在无需access hash即可发送消息的方法?

不行。Telegram的MTProto协议出于安全和反垃圾机制的设计,发送消息到陌生用户时必须提供正确的access hash,无法绕开这一要求。

2. 仅用公开用户ID程序化获取access hash的方法

获取access hash的前提是目标用户对你的账号可见,以下分库给出可行方案:

gram.js实现

如果目标用户有公开username,可通过username关联数字ID获取实体;若已添加为联系人或有过交互,直接用数字ID即可获取:

const { TelegramClient } = require('telegram');
const { StringSession } = require('telegram/sessions');

const apiId = YOUR_API_ID;
const apiHash = 'YOUR_API_HASH';
const stringSession = new StringSession('YOUR_SESSION');
const client = new TelegramClient(stringSession, apiId, apiHash, { connectionRetries: 5 });

async function getAccessHash(userId) {
    await client.connect();
    try {
        // 尝试直接通过ID获取实体(仅当有交互/在联系人时有效)
        const entity = await client.getEntity(userId);
        return entity.accessHash;
    } catch (error) {
        // 若失败,尝试通过username搜索(需提前知道目标用户的username)
        const searchResults = await client.invoke(new Api.contacts.Search({
            q: 'TARGET_USERNAME',
            limit: 1
        }));
        if (searchResults.users.length > 0) {
            const user = searchResults.users[0];
            if (user.id === userId) {
                return user.accessHash;
            }
        }
        throw new Error('无法获取access hash:用户不可见或未找到对应username');
    }
}

Telethon实现

逻辑与gram.js一致,通过实体查询或搜索获取:

from telethon import TelegramClient
from telethon.tl.types import User

api_id = YOUR_API_ID
api_hash = 'YOUR_API_HASH'
session_name = 'telethon_session'

client = TelegramClient(session_name, api_id, api_hash)

async def get_access_hash(user_id):
    await client.start()
    try:
        # 直接通过ID获取实体
        entity = await client.get_entity(user_id)
        if isinstance(entity, User):
            return entity.access_hash
    except:
        # 通过username搜索匹配
        results = await client.search_users('TARGET_USERNAME')
        for user in results:
            if user.id == user_id:
                return user.access_hash
    raise ValueError('无法获取目标用户的access hash')

TDLib实现

通过getUser或searchPublicChats接口获取用户实体:

#include <td/telegram/Client.h>
#include <td/telegram/td_api.h>

using namespace td;

void get_access_hash(Client &client, int64_t user_id) {
    // 尝试直接获取用户
    auto user_request = make_object<td_api::getUser>(user_id);
    client.send(std::move(user_request), [&client, user_id](ObjectPtr<Object> object) {
        if (auto error = object->as_error()) {
            // 失败则尝试搜索公开username
            auto search_request = make_object<td_api::searchPublicChats>("TARGET_USERNAME");
            client.send(std::move(search_request), [&client, user_id](ObjectPtr<Object> search_obj) {
                if (auto chats = search_obj->as_chats()) {
                    for (auto &chat : chats->chats_) {
                        if (auto public_chat = chat->as_publicChat()) {
                            if (public_chat->user_id_ == user_id) {
                                // 再次获取用户实体
                                auto user_req = make_object<td_api::getUser>(user_id);
                                client.send(std::move(user_req), [](ObjectPtr<Object> user_obj) {
                                    if (auto user = user_obj->as_user()) {
                                        int64_t access_hash = user->access_hash_;
                                    }
                                });
                            }
                        }
                    }
                }
            });
        } else if (auto user = object->as_user()) {
            int64_t access_hash = user->access_hash_;
        }
    });
}

注意:如果目标用户无公开username,且未与你的账号有过交互、不在联系人列表中,无法仅通过数字ID获取access hash——这是Telegram的隐私限制。

3. 替代方案或变通方法

如果无法直接获取access hash,可尝试以下变通方式:

添加临时联系人

通过contacts.addContact接口将目标用户添加为联系人(无需对方同意),添加成功后即可获取其access hash:

async function addContactAndSend(userId, message) {
    await client.connect();
    // 添加联系人(accessHash填0即可发起请求)
    await client.invoke(new Api.contacts.AddContact({
        id: new Api.InputUser({ userId, accessHash: 0 }),
        firstName: "临时联系人",
        lastName: "",
        phone: "",
        addPhonePrivacyException: false
    }));
    // 添加后获取实体并发送消息
    const entity = await client.getEntity(userId);
    await client.sendMessage(entity, { message });
    console.log("消息发送成功");
}

公共群组/频道中转

若目标用户加入了某个公共群组或频道,可通过获取群组参与者列表找到目标用户的实体,进而拿到access hash:

async function getAccessHashFromGroup(userId, groupId) {
    await client.connect();
    const participants = await client.getParticipants(groupId, { limit: 100 });
    for (const participant of participants) {
        if (participant.userId === userId) {
            return participant.accessHash;
        }
    }
    throw new Error("目标用户不在该群组中");
}

内容的提问来源于stack exchange,提问作者Drop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 14:22:05