LoginSignup
6
8

More than 3 years have passed since last update.

Go の net/http でベーシック認証の client/server を作成する

Last updated at Posted at 2019-05-23

BackGround

筆者は普段は C で組み込み技術の開発をしています。
そんな筆者ですが、業務で web技術 を活用したい、と常々考えています。

そこで、web技術の基礎として、ベーシック認証ができる client/server を作成してみましたので紹介します。

今、web 技術の基本として、O'REILLY の Real World HTTP という書籍を読んでいるので、
その本で書かれている http の仕様を踏まえつつ、実践をしてみたものとなります。

Target

  • Go の標準パッケージ net/http のベーシック認証の取り扱い方がわかる
  • Go で実装した client/server を実際に動かしてベーシック認証を試せる

ベーシック認証

Basic認証(ベーシックにんしょう、Basic Authentication)とは、HTTPで定義される認証方式の一つ。

基本認証と呼ばれることも。

Basic認証では、ユーザ名とパスワードの組みをコロン ":" でつなぎ、Base64でエンコードして送信する。

このため、盗聴や改竄が簡単であるという欠点を持つが、ほぼ全てのWebサーバおよびブラウザで対応しているため、広く使われている。

出典: フリー百科事典『ウィキペディア(Wikipedia)』

つくるもの

  • client
    • server へベーシック認証付きのリクエストを送信し、server のレスポンスの body を標準出力へ出力する
  • server
    • client のリクエストをベーシック認証にて認証し、認証が成功したかどうかで異なるレスポンスを送信する
      • 成功した場合は Authed とレスポンスを送信する
      • 失敗した場合は Not authorized とレスポンスを送信する

できたもの

client/server は以下のように動きます。

先に server を起動し、その後 client を起動すると、
認証が成功した旨がレスポンスとして得られます。

# server プログラムを起動する
$ ./server

# client プログラムを実行する
$ ./client
Authed

SourceCode

ソースコードは以下のようになりました。

client.go
package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "time"
)

func main() {
    client := &http.Client{Timeout: time.Duration(10) * time.Second}

    req, err := http.NewRequest("GET", "http://localhost:18888/basic", nil)
    if err != nil {
        log.Fatal(err)
    }
    req.SetBasicAuth("user", "pass")
    resp, err := client.Do(req)
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    fmt.Println(string(getContent(resp)))
}

func getContent(resp *http.Response) []byte {
    b, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }
    return b
}

client は、req オブジェクトへ、 SetBasicAuth メソッドを使って、
ベーシック認証のユーザとパスワードを与えるだけでベーシック認証に対応できます。

server.go
package main

import (
    "fmt"
    "log"
    "net/http"
)

const (
    basicAuthUser     = "user"
    basicAuthPassword = "pass"
)

func main() {
    http.HandleFunc("/basic",
        func(w http.ResponseWriter, r *http.Request) {
            if user, pass, ok := r.BasicAuth(); !ok || user != basicAuthUser || pass != basicAuthPassword {
                w.Header().Add("WWW-Authenticate", `Basic realm="my private area"`)
                w.WriteHeader(http.StatusUnauthorized)
                http.Error(w, "Not authorized", 401)
                return
            }
            _, err := fmt.Fprintf(w, "Authed\n")
            if err != nil {
                log.Fatal(err)
            }
        },
    )
    log.Println(http.ListenAndServe(":18888", nil))
}

server は、req オブジェクトへ、 BasicAuth メソッドを使って、
ベーシック認証のユーザとパスワードを取得し評価するだけでベーシック認証に対応できます。

Roundup

  • パッケージの中で相対的に低水準な net/http でも、十分に抽象化されていて、簡単に取り扱うことができる
  • リクエストの送信や、サーバの作成自体も net/http にてシンプルに実装ができる

Reference

6
8
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
8