RubyからBasic認証をともなうアクセス

当然ですが、認証が必要なので普通にGETするだけでは無理で、

require "net/http"
require "uri"

url = "http://localhost:4002/a/a.php"
uri = URI.parse url

=begin
# 普通にアクセスするだけではだめ
res = Net::HTTP.start(uri.host, uri.port) do |http|
http.get "/a/a.php"
end
if res.is_a?(Net::HTTPSuccess)
puts res.body.gsub /\r\n|<br>/, "\n"
else
puts res.class # Net::HTTPUnauthorized
end
=end

# Net::HTTP::Getを使う
res = Net::HTTP.start(uri.host, uri.port) do |http|
req = Net::HTTP::Get.new "/a/a.php"
req.basic_auth "root", "pass"
res = http.request req
print res.body.gsub /\r\n|<br>/i, "\n"
end

ブラウザでは一旦認証が成功するとブラウザを停止するまで
最ログインできないので、コードからアクセスしたほうが
テスト時は便利かもしれない。

サーバー側のコード(PHP)。
(セキュリティ的な配慮はない(Basic認証だし)。)
コードが横に広がるのがイヤだったので変数が多めとなった。

<?php
function h($s) {
    return htmlspecialchars($s, ENT_QUOTES, "UTF-8");
}

/* ※セキュリティは考慮していません */
function require_basic_auth() {
    header(
        'WWW-Authenticate: Basic realm=' . 
        '"Enter your name and pass"'
    );
    header('Content-Type: text/html; charset=UTF-8');
}

/* 別スクリプトで隔離する */
$table = [
    "user_a" => "a123",
    "b_user" => "456b",
];

$is_valid_user = isset($_SERVER["PHP_AUTH_USER"]);
$is_valid_pw = isset($_SERVER["PHP_AUTH_PW"]);
$is_invalid = !$is_valid_user || !$is_valid_pw;

/* 認証失敗(1) */
if ($is_invalid) {
    require_basic_auth();
} else {
    $user = $_SERVER["PHP_AUTH_USER"];
    $pass = $_SERVER["PHP_AUTH_PW"];

    /* 認証失敗(2) */
    $is_user = array_key_exists($user, $table);
    if ($is_user) {
        $is_collect_pw = $pass === $table[$user];
        if ($is_collect_pw) {

            /* 認証成功 */
            echo "User: " . h($user) . "<br>";
            echo "Password: " . h($pass) . "<br>";

        } else {
            echo "Invalid password<br>";
            require_basic_auth();
        }
    } else {
        echo "Invalid user (user does not exists)<br>";
        require_basic_auth();
    }
}
?>

認証成功時以外はすべてエラーとしてまとめた方がよかった。