社内システムでかつ、外部公開をする場合に社内なら認証なし+社外からは認証かけたい場合のIPベースでの解決方法
RailsでのBasic認証
https://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Basic.html
まずは公式参照
ほぼこの内容なので、条件をローカルネットワークなら認証必要に変える。
ちなみにこの公式の内容だと通常のログイン認証と併用できたりする。管理者アクセスとかに使えるかも。
application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
http_basic_authenticate_with name: "user", password: "pass"
end
IPベースの判定
CIDRベースで指定したい。
IPAddr
かnetaddr
でいけるみたい。今回はnetaddr
の方を使う。
github
https://github.com/dspinhirne/netaddr-rb
readmeに使い方はないので、テストケースを参照。
サブネットで判定
https://github.com/dspinhirne/netaddr-rb/blob/master/test/ipv4net_test.rb
ここにいろいろあるテストケースから抜粋
def test_contains
net = NetAddr::IPv4Net.parse("1.0.0.8/29")
ip1 = NetAddr::IPv4.parse("1.0.0.15")
ip2 = NetAddr::IPv4.parse("1.0.0.16")
ip3 = NetAddr::IPv4.parse("1.0.0.7")
assert_equal(true, net.contains(ip1))
assert_equal(false, net.contains(ip2))
assert_equal(false, net.contains(ip3))
end
このへんですね。
実際に書くと
def is_local_access?
return NetAddr::IPv4Net.parse('192.168.1.0/24').contains(NetAddr::IPv4.parse(request.ip))
end
こんな感じでしょうか。
これで192.168.1.0/24のネットワークが判定できる。
(nginxとかリバースプロキシ挟んでるときはrequest.ip
かrequest.remote_ip
、nginxの設定によるかも)
もうちょっとやるならlocalリクエストも判定しておいたほうがいい。
request.local?
application_controller
application_controller.rb
require 'netaddr'
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
http_basic_authenticate_with name: "user", password: "pass", unless: : is_local_access?
private
def is_local_access?
return NetAddr::IPv4Net.parse('192.168.1.0/24').contains(NetAddr::IPv4.parse(request.ip))
end
end