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

如何在Ruby on Rails中使用Azure托管标识访问Azure PubSub?

在Ruby on Rails应用中用Azure托管标识替代Primary Key连接Azure PubSub Service

一、Azure端配置

  • 给ROR应用所在的Azure资源(如App Service、虚拟机)启用托管标识:
    • 系统分配标识:直接在资源的"标识"选项卡启用,自动创建关联的AD标识。
    • 用户分配标识:先创建用户分配标识,再关联到目标资源。
  • 为托管标识分配Azure PubSub权限:
    • 进入Azure Web PubSub实例的"访问控制(IAM)"选项卡,添加角色分配。
    • 推荐分配Web PubSub Service Contributor角色(适用于完整权限场景),或更细粒度的角色如Web PubSub Token Contributor(仅用于生成客户端令牌)。

二、ROR应用代码改造

1. 依赖准备

在Gemfile中添加HTTP请求依赖:

gem 'faraday'

执行bundle install安装依赖。

2. 实现Azure AD令牌获取方法

通过Azure实例元数据服务(IMDS)获取针对Web PubSub的AD令牌(仅在Azure环境中可用,本地开发可使用Azure CLI临时令牌):

def get_azure_ad_token
  resource = "https://webpubsub.azure.com/"
  # 若使用用户分配标识,需追加&client_id=你的用户分配标识ID
  imds_url = "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=#{URI.encode_www_form_component(resource)}"

  response = Faraday.get(imds_url) do |req|
    req.headers["Metadata"] = "true"
  end

  raise "获取Azure AD令牌失败: #{response.status} - #{response.body}" unless response.success?

  JSON.parse(response.body)["access_token"]
end

3. 替换原令牌生成逻辑,调用PubSub API生成客户端令牌

不再使用Primary Key签名JWT,而是用AD令牌认证后调用PubSub的REST API生成客户端访问令牌:

def get_auth_token(hub)
  pubsub_service_name = "<pubsub-service>" # 替换为你的PubSub服务名称
  pubsub_endpoint = "https://#{pubsub_service_name}.webpubsub.azure.com"
  ad_token = get_azure_ad_token

  # 调用PubSub的生成令牌API
  api_url = "#{pubsub_endpoint}/api/hubs/#{hub}/:generateToken?api-version=2023-07-01-preview"
  # 可根据业务需求调整payload参数,如userId、roles、过期时间等
  token_payload = {
    "userId" => current_user&.id, # 可选,绑定客户端用户ID
    "roles" => ["webpubsub.sendToGroup", "webpubsub.joinLeaveGroup"], # 可选,设置客户端权限
    "expiresIn" => 3600 # 可选,令牌过期时间(秒)
  }

  response = Faraday.post(api_url) do |req|
    req.headers["Authorization"] = "Bearer #{ad_token}"
    req.headers["Content-Type"] = "application/json"
    req.body = token_payload.to_json
  end

  raise "生成PubSub客户端令牌失败: #{response.status} - #{response.body}" unless response.success?

  JSON.parse(response.body)["token"]
end

4. 保持连接URL生成逻辑不变

原get_connection_url方法无需大幅修改,只需确保传入hub参数:

def get_connection_url(hub)
  pubsub_service_name = "<pubsub-service>" # 替换为你的PubSub服务名称
  "wss://#{pubsub_service_name}.webpubsub.azure.com/client/hubs/#{hub}?access_token=#{get_auth_token(hub)}"
end

三、优化建议

  • 令牌缓存:Azure AD令牌默认有效期1小时,可通过Rails.cache缓存令牌,避免频繁调用IMDS:
    def get_azure_ad_token
      cache_key = "azure_ad_token_webpubsub"
      cached_token = Rails.cache.read(cache_key)
      return cached_token if cached_token.present?
    
      # 原令牌获取逻辑...
      token = JSON.parse(response.body)["access_token"]
      expires_on = JSON.parse(response.body)["expires_on"].to_i
      expires_in = expires_on - Time.now.to_i
    
      Rails.cache.write(cache_key, token, expires_in: expires_in - 60) # 提前60秒过期,避免令牌失效
      token
    end
    
  • 本地开发适配:本地开发时无法访问IMDS,可通过Azure CLI获取令牌并设置为环境变量:
    # 执行Azure CLI命令获取令牌
    az account get-access-token --resource https://webpubsub.azure.com/ --query accessToken -o tsv
    # 将令牌设置为环境变量,在代码中优先读取
    
    修改get_azure_ad_token方法添加本地 fallback:
    def get_azure_ad_token
      return ENV["AZURE_AD_TOKEN"] if Rails.env.development? && ENV["AZURE_AD_TOKEN"].present?
    
      # 原IMDS获取逻辑...
    end
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 04:44:58