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 のリクエストをベーシック認証にて認証し、認証が成功したかどうかで異なるレスポンスを送信する
できたもの
client/server は以下のように動きます。
先に server を起動し、その後 client を起動すると、
認証が成功した旨がレスポンスとして得られます。
# server プログラムを起動する
$ ./server
# client プログラムを実行する
$ ./client
Authed
SourceCode
ソースコードは以下のようになりました。
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
メソッドを使って、
ベーシック認証のユーザとパスワードを与えるだけでベーシック認証に対応できます。
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
にてシンプルに実装ができる