java-具有Spring Security和Rabbitmq的OAuth2授权
作者:互联网
当前,我们有许多与REST端点和RabbitMQ队列进行通信的Spring微服务.我们刚刚在所有服务上实现了OAuth2安全性,并且REST端点得到了适当的保护.
我们有一个编写的库,该库创建RabbitTemplate和AmqpAdmin Bean,因此不必在每个服务中都完成样板代码.我们正在使用特定用户(普通用户和管理员)连接到Spring中的RabbitMQ服务器.我们不想以个人用户身份连接到RabbitMQ服务器.
如果我们在Rabbit消息头中传递访问令牌,是否可以将RabbitTemplate配置为在处理消息之前检查令牌?是否可以/应该在模板的AfterReceive / BeforePublish处理器中全局执行此操作?还是需要在每个侦听器方法中单独检查此内容?
谢谢
解决方法:
我可以通过创建自定义MessageListenerContainerFactory和MessageListenerContainer来制定解决方案.
CustomMessageListenerContainerFactory.java:
public class CustomMessageListenerContainerFactory extends AbstractRabbitListenerContainerFactory {
DefaultTokenServices tokenServices;
public CustomMessageListenerContainerFactory(DefaultTokenServices tokenServices) {
this.tokenServices = tokenServices;
}
/**
* Create an empty container instance.
*
* @return the new container instance.
*/
@Override
protected CustomMessageListenerContainer createContainerInstance() {
return new CustomMessageListenerContainer(tokenServices);
}
}
CustomMessageListenerContainer.java:
public class CustomMessageListenerContainer extends SimpleMessageListenerContainer {
private final static String errorMessage = "No valid credentials found in request: {}";
private final static String handlingMessage = "Handling queue: {}";
private final static String receivedMessage = "Received Message: {}";
private final static Logger logger = LoggerFactory.getLogger(CustomMessageListenerContainer.class);
private DefaultTokenServices tokenServices;
/**
* Constructor
*
* @param tokenServices The instance of DefaultTokenServices used to decrypt the access token.
*/
public CustomMessageListenerContainer(DefaultTokenServices tokenServices) {
this.tokenServices = tokenServices;
}
/**
* This method checks to see if there is a valid authorization
*
* @param channel The AMQP channel on which the message was published.
* @param messageIn The incoming message.
* @throws Exception Throws an exception when there are no valid credentials in the message.
*/
@Override
protected void executeListener(Channel channel, Message messageIn) throws Exception {
logger.info(handlingMessage, (Object[]) getQueueNames());
logger.info(receivedMessage, BeanUtils.beanProperties(messageIn));
if (messageIn.getMessageProperties().getHeaders().keySet().stream().anyMatch(t -> Objects.equals(t.toLowerCase(), "authorization"))) {
String accessKey = messageIn.getMessageProperties()
.getHeaders()
.keySet()
.stream()
.filter(t -> Objects.equals(t.toLowerCase(), "authorization"))
.findFirst()
.get();
OAuth2Authentication auth = tokenServices.loadAuthentication(messageIn.getMessageProperties().getHeaders().get(accessKey).toString());
// If the token is expired, there will be no auth.
if (auth != null) {
SecurityContextHolder.getContext().setAuthentication(auth);
super.executeListener(channel, messageIn);
return;
}
}
rejectMessage(channel, messageIn);
}
private void rejectMessage(Channel channel, Message messageIn) throws Exception {
logger.info(errorMessage, (Object[]) getQueueNames());
String localMessage = errorMessage.replace("{}", String.join(", ", getQueueNames()));
if (messageIn.getMessageProperties().getReplyTo() != null) {
channel.basicPublish("",
messageIn.getMessageProperties().getReplyTo(),
new AMQP.BasicProperties.Builder()
.contentType("application/json")
.correlationId(messageIn.getMessageProperties().getCorrelationId())
.build(),
"{\"errorMessage\":\"".concat(localMessage).concat("\"}").getBytes());
}
throw new AmqpRejectAndDontRequeueException(localMessage);
}
}
CustomRabbitListenerConfigurer.java:
... @Override public void configureRabbitListeners(final RabbitListenerEndpointRegistrar registrar) { registrar.setMessageHandlerMethodFactory(messageHandlerMethodFactory()); CustomMessageListenerContainerfactory factory = new CustomMessageListenerContainerfactory(tokenServices); ConnectionFactory connectionFactory = context.getBean(ConnectionFactory.class); factory.setConnectionFactory(connectionFactory); registrar.setContainerFactory(factory); } ...
标签:spring-amqp,spring-security-oauth2,spring-rabbit,spring,java 来源: https://codeday.me/bug/20191109/2011016.html