从Databricks读取Azure Event Hub/IoT Hub报401 SAS认证禁用错误
问题解决:Azure IoT Hub读取时SAS认证禁用报错(401)
问题背景
使用Databricks IIoT端到端指南测试Azure Event Hub与IoT Hub,已创建格式正确的Event Hub兼容连接字符串:Endpoint=sb://iothub-ns-xxx-xxx-xxx.servicebus.windows.net/;SharedAccessKeyName=iothubowner;SharedAccessKey=XXXX=;EntityPath=xxxx-iothub
已确认Event Hub命名空间本地认证已启用,但读取IoT Hub数据时仍报错:
java.util.concurrent.ExecutionException: com.microsoft.azure.eventhubs.AuthorizationFailedException: status-code: 401, status-description: LocalAuthDisabled: Authorization failed because SAS authentication has been disabled for the namespace.
失败代码片段
# Schema of incoming data from IoT hub schema = "timestamp timestamp, deviceId string, temperature double, humidity double, windspeed double, winddirection string, rpm double, angle double" # Read directly from IoT Hub using the EventHubs library for Databricks iot_stream = ( spark.readStream.format("eventhubs") # Read from IoT Hubs directly .options(**ehConf) # Use the Event-Hub-enabled connect string .load() # Load the data .withColumn('reading', F.from_json(F.col('body').cast('string'), schema)) # Extract the "body" payload from the messages .select('reading.*', F.to_date('reading.timestamp').alias('date')) # Create a "date" field for partitioning ) # Split our IoT Hub stream into separate streams and write them both into their own Delta locations write_turbine_to_delta = ( iot_stream.filter('temperature is null') # Filter out turbine telemetry from other data streams .select('date','timestamp','deviceId','rpm','angle') # Extract the fields of interest .writeStream.format('delta') # Write our stream to the Delta format .partitionBy('date') # Partition our data by Date for performance .option("checkpointLocation", CHECKPOINT_PATH + "turbine_raw") # Checkpoint so we can restart streams gracefully .start(BRONZE_PATH + "turbine_raw") # Stream the data into an ADLS Path ) write_weather_to_delta = ( iot_stream.filter(iot_stream.temperature.isNotNull()) # Filter out weather telemetry only .select('date','deviceid','timestamp','temperature','humidity','windspeed','winddirection') .writeStream.format('delta') # Write our stream to the Delta format .partitionBy('date') # Partition our data by Date for performance .option("checkpointLocation", CHECKPOINT_PATH + "weather_raw") # Checkpoint so we can restart streams gracefully .start(BRONZE_PATH + "weather_raw") # Stream the data into an ADLS Path ) # Create the external tables once data starts to stream in while True: try: spark.sql(f'CREATE TABLE IF NOT EXISTS turbine_raw USING DELTA LOCATION "{BRONZE_PATH + "turbine_raw"}"') spark.sql(f'CREATE TABLE IF NOT EXISTS weather_raw USING DELTA LOCATION "{BRONZE_PATH + "weather_raw"}"') break except: pass
解决方案
1. 检查IoT Hub自身的本地身份验证设置
Event Hub兼容端点的SAS认证不仅依赖Event Hub命名空间配置,还要确保IoT Hub本身允许SAS认证:
- 进入Azure门户的IoT Hub资源
- 导航至安全性 > 本地身份验证
- 确认**共享访问签名(SAS)**选项处于启用状态
2. 验证共享访问策略的权限
你使用的iothubowner策略权限足够,但需确认其包含**服务连接(Service Connect)**权限:
- 在IoT Hub的共享访问策略中找到
iothubowner - 检查权限列表,确保勾选了
Service Connect
3. 确认Event Hub命名空间的SAS认证生效
有时设置可能未即时生效,或选错了命名空间:
- 找到IoT Hub对应的Event Hub命名空间(可在IoT Hub的内置终结点中查看Event Hub兼容端点的命名空间)
- 进入该命名空间的安全性 > 本地身份验证
- 确保**允许本地身份验证(SAS密钥)**已开启,且设置已保存生效
4. 检查连接字符串格式与EntityPath
确认连接字符串中的EntityPath是你的IoT Hub名称,而非Event Hub实体名称:
- IoT Hub的Event Hub兼容连接字符串中,
EntityPath必须是IoT Hub的名称,不能填自定义Event Hub实体
5. 排查网络限制(可选)
若Event Hub命名空间配置了防火墙或虚拟网络,需确保Databricks工作区的IP地址在允许列表中:
- 进入Event Hub命名空间的网络设置
- 确认Databricks的出站IP已添加至允许列表,或设置为允许所有网络(测试用)
内容的提问来源于stack exchange,提问作者Stian
相关产品推荐
相关产品推荐

