Restringir o acesso IP em trilhos

Não é incomum restringir o acesso a algumas partes do seu aplicativo por IP.
Recentemente, tive que implementar essa restrição como uma solução rápida para um cliente corporativo –
até que uma restrição mais permanente de acesso usando LDAP esteja em vigor.

A implementação mais fácil, é apenas verificar em um before_actionfiltro o IP do usuário atual ( como sugerem muitas respostas do SO )

O código de respostas StackOverflow é mais ou menos assim:

class ApplicationController < ActionController::Base
before_action
:filter_ip_address

protected

def filter_ip_address
current_ip_address
= request.env['HTTP_X_REAL_IP'] || request.env['REMOTE_ADDR']
head
:unauthorized if current_ip_address == "XX.XX.XX.XX"
end
end

Mas este código tem as seguintes advertências (algumas foram mais relevantes para mim):
– Não há suporte para intervalos de IP
– O filtro é implementado no controlador, onde preciso que seja utilizado em vários controladores
– O IP permitido está codificado

Portanto, para abordar cada ponto:
– Suporte para intervalos de IP: podemos usar a biblioteca integrada IPAddr , criar uma instância com nosso formato CIDR para intervalo de endereços IP e usar o método para determinar se o IP do usuário atual está no intervalo. – O filtro precisa ser reutilizado em vários controladores: aqui, há muitas abordagens diferentes. Eu poderia criar uma classe de controlador implementando o filtro nela e fazer com que todos os controladores que precisassem de proteção IP herdassem dela. Mas na guerra da “Composição sobre a herança”, sou a favor da composição. Então criei um módulo implementando o filtro para ser incluído em cada controlador. – IPs são codificados: fora do escopo aqui, apenas uma implementação enfadonha de CRUD para cada cliente do nosso lado.include?

Então, como foi o código no final?

O módulo para os filtros, a ser incluído em cada controlador, tinha a seguinte aparência:

require 'ipaddr'

module AdminAuthorizationFilters

def self.included(base)
base.before_action :filter_ips_for_brand, :many, :other, :possible, :filters
end

# Protected methods
# --------------------------------------------------------------------------------
protected

# For the current user, if his brand has a `whitelisted_ips` list, then verify the
# current connection is from a verified IP
def filter_ips_for_brand
user_ip
= IPAddr.new(request.remote_ip)
# An array of IPs and IP ranges that should be allowed. Stored on the current user.
allowed_ips
= current_user.brand.whitelisted_ips
# Validate IP only if allowed_ips array is set, otherwise there is no IP restriction
if allowed_ips
verified
= false
allowed_ips
.each do |allowed_ip|
allowed_ip
= IPAddr.new(allowed_ip)
if allowed_ip.include?(user_ip)
verified
= true
end
end
# Redirect back to main page if not verified
unless verified
redirect_to
"/"
end
end
end
end

E então em cada controlador que precisa utilizar esses filtros:

class MyController < ApplicationController
# Include the admin authorization "before_action" filters
include
AdminAuthorizationFilters

...
end

Viola. Implementação rápida para restrição de acesso IP.