RabbitMQ集成Keycloak授权时遭遇访问拒绝问题求助
操作背景
以下是我做过的配置和测试步骤:
1. RabbitMQ配置文件设置
创建rabbitmq.config文件,内容如下:
[ {rabbit, [ {auth_backends, [rabbit_auth_backend_oauth2]} ]}, {rabbitmq_auth_backend_oauth2, [ {resource_server_id, <<"rabbitmq">>}, {extra_scopes_source, <<"extra_scope">>}, {preferred_username_claims, [<<"user_name">>]}, {key_config, [ {jwks_url, <<"http://0.0.0.0:8080:8080/realms/test/protocol/openid-connect/certs">>} ]} ]} ].
将文件移至/etc/rabbitmq并重启RabbitMQ服务。
2. Keycloak配置
启动Keycloak,创建名为test的Realm,添加两个客户端:
- 用于向RabbitMQ发消息的客户端应用(
mgt_api_client) - 作为资源服务器的RabbitMQ客户端
3. 客户端授权与Token信息
配置mgt_api_client使用client_credential授权类型,获取的Access Token解码后内容:
{ "exp": 1686908069, "iat": 1686907769, "jti": "db13bb2d-bb4f-40ea-ae19-8deaf8dfc4ce", "iss": "http://localhost:8080/realms/test", "aud": "rabbitmq", "sub": "15f03347-e2fc-4f8c-9743-f4dfd59f67fe", "typ": "Bearer", "azp": "mgt_api_client", "scope": "email rabbitmq.tag:management", "clientId": "mgt_api_client", "clientHost": "127.0.0.1", "email_verified": false, "clientAddress": "127.0.0.1" }
4. Python测试代码
import pika import jwt import datetime connection_parameters = pika.ConnectionParameters(host='localhost') # Connect to RabbitMQ and create a channel connection = pika.BlockingConnection(connection_parameters) channel = connection.channel() # Declare the exchange exchange_name = 'hungdeptrai' channel.exchange_declare(exchange=exchange_name, exchange_type='direct', durable=True) jwt_token = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJHbmwyWmxiUmgzckFyNld5bWM5ODhfNWNZN1Q1R3VlUGQ1ZHBKbFhESlVrIn0.eyJleHAiOjE2ODY5MDgwNjksImlhdCI6MTY4NjkwNzc2OSwianRpIjoiZGIxM2JiMmQtYmI0Zi00MGVhLWFlMTktOGRlYWY4ZGZjNGNlIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0IiwiYXVkIjoicmFiYml0bXEiLCJzdWIiOiIxNWYwMzM0Ny1lMmZjLTRmOGMtOTc0My1mNGRmZDU5ZjY3ZmUiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJtZ3RfYXBpX2NsaWVudCIsInNjb3BlIjoiZW1haWwgcmFiYml0bXEudGFnOm1hbmFnZW1lbnQiLCJjbGllbnRJZCI6Im1ndF9hcGlfY2xpZW50IiwiY2xpZW50SG9zdCI6IjEyNy4wLjAuMSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiY2xpZW50QWRkcmVzcyI6IjEyNy4wLjAuMSJ9.2FeD7Ba4hQGc__XfSX9PlUNR4-aauxl6TVjZOpTIkSNObPJ3O05b_W3ivEB9agzxPfrBhBRGb79OkIP8q3eWgXk7VYr93-BLRHtGQ_v9MrLOaKFHqZULT0F62-v57H_TD9LQ7MNRmRjUztpcUXI8_oSsThapiNuEMPHMJ6cmsv32kJ4GnxwDHUz7UQoFvnIIaqVejoTkLKQLN8wWA6uk3o8slUY2f9-smZTm8XQQfdwBNBKo0Np40nqY6B5Icxckqw_0owVQMW2ANoBVReunXpBod9dwUJuXUdNTu3BZANfHN886laO1VDLQunUfTdTg6VWQTP4qQ5Fs2Bm9a0ebQw" # Publish the message routing_key = 'my_queue' message_body = 'Hello, World!' message_properties = pika.BasicProperties(headers={'Authorization': f'Bearer {jwt_token}'}) channel.basic_publish(exchange=exchange_name, routing_key=routing_key, body=message_body, properties=message_properties) # Close the connection connection.close()
运行代码后始终出现Access Refused错误,以下是具体排查方向:
排查点1:JWKS URL格式错误
rabbitmq.config中的jwks_url存在端口重复问题:http://0.0.0.0:8080:8080/...,正确地址应为http://0.0.0.0:8080/realms/test/protocol/openid-connect/certs或http://localhost:8080/realms/test/protocol/openid-connect/certs(需确保RabbitMQ能访问到Keycloak服务)。修改配置后必须重启RabbitMQ生效。
排查点2:Token传递时机错误
RabbitMQ OAuth2插件默认要求在连接建立阶段传递Token,而非发布消息时通过headers传递。当前代码在basic_publish时才添加授权头,此时连接已建立,插件无法获取Token验证。
正确传递方式:在建立连接时传入Token:
connection_parameters = pika.ConnectionParameters( host='localhost', credentials=pika.PlainCredentials( username='', # OAuth2模式下用户名留空 password=jwt_token ) ) connection = pika.BlockingConnection(connection_parameters)
排查点3:RabbitMQ权限策略未配置
即使Token验证通过,RabbitMQ仍需对应策略允许客户端操作目标交换器和队列:
- 登录RabbitMQ管理后台,进入
Admin->Policies - 创建策略,匹配交换器
hungdeptrai和队列my_queue,授予management标签对应权限 - 确保策略
Apply to选择Exchanges and Queues,权限设置为.*(或按需配置)
也可通过命令行添加策略:
rabbitmqctl set_policy test-policy "^hungdeptrai$|^my_queue$" '{"tags":["management"]}' --apply-to all
排查点4:Keycloak客户端配置检查
- 确认RabbitMQ资源服务器客户端的
Access Type设为confidential(client_credential模式适配) - 确认
mgt_api_client的Service Accounts Enabled已开启(client_credential依赖服务账户)
排查点5:查看RabbitMQ日志定位原因
直接查看RabbitMQ日志文件(通常路径/var/log/rabbitmq/rabbit@<hostname>.log),日志会明确报错原因,比如Token验证失败、JWKS获取失败、权限不足等,是最直接的排查依据。
内容的提问来源于stack exchange,提问作者hung

