如何在NEAR协议合约中获取委托操作的账户ID?
在NEAR合约中兼容标准交易与委托操作获取用户账户ID的解决方案
当使用委托操作(delegate actions)时,env::signer_account_id()会返回委托签名者的账户ID,而非发起操作的底层用户ID,直接导致权限检查逻辑失效。针对这个问题,分两种场景给出解决方案:
场景1:使用NEAR原生Delegate Action
如果是用户签署Delegate Action后由第三方提交交易,此时当前合约调用的Action是由用户签名的,env::signer_account_id()会直接返回用户的账户ID,env::transaction_signer_account_id()才是提交交易的第三方账户ID。这种情况下你的原有权限检查逻辑不需要修改,报错大概率是因为你用的不是原生Delegate Action,而是中继合约代理调用。
场景2:中继合约代理调用(第三方账户代用户操作)
如果是中继合约获得用户授权后直接调用你的合约,env::signer_account_id()返回的是中继合约ID,需要做以下调整:
- 修改合约方法,新增可选的
user_id参数,让中继合约传递实际用户的账户ID - 在合约中维护授权关系,验证中继合约是否拥有该用户的操作权限
修改后的权限检查示例代码:
use near_sdk::{env, require, near_bindgen}; #[near_bindgen] #[derive(Default)] pub struct MyContract { owner: String, // 存储用户与授权中继的映射:用户ID => 授权中继列表 authorized_relayers: std::collections::HashMap<String, Vec<String>>, } #[near_bindgen] impl MyContract { // 用户给中继合约授权的方法 pub fn add_authorized_relayer(&mut self, relayer_id: String) { let user_id = env::signer_account_id(); self.authorized_relayers.entry(user_id) .or_insert_with(Vec::new) .push(relayer_id); } // 需要权限校验的业务方法,兼容直接调用和中继调用 pub fn restricted_method(&self, user_id: Option<String>) { // 确定实际操作的用户ID let actual_user = match user_id { // 中继调用时,验证中继是否被用户授权 Some(id) => { let relayer_id = env::signer_account_id(); require!( self.authorized_relayers.get(&id) .map_or(false, |relayers| relayers.contains(&relayer_id)), "ERR: relayer not authorized" ); id } // 用户直接调用时,取签名者ID None => env::signer_account_id(), }; // 核心权限检查 require!(actual_user == self.owner, "ERR: not the owner"); } }
关键说明
- 原生Delegate Action场景下,合约能直接通过
env::signer_account_id()拿到用户ID,无需额外处理 - 中继代理场景下,必须通过参数传递用户ID并验证授权,否则合约无法识别实际操作人
内容的提问来源于stack exchange,提问作者janek-cosmose
相关产品推荐
相关产品推荐

