mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-19 11:19:36 +00:00
Bring the READMEs and the docs pages (en and ja) in line with the current header: - Fix the client sample that does not compile, the Transfer-Encoding statement for default headers, the verifier callback comment, the thread pool spawn rule, the sanitize_filename description, and the inverted Accept-Encoding sentence. - Describe recent behaviour: TLS errors behind Read/Write failures, Host validation, Connection: close for a body without length, content_reader rules, refused CONNECT, WebSocketClient proxies, CPPHTTPLIB_INTERIM_RESPONSE_MAX_COUNT, the SSE event size limit, and the payload limit of the Stream API. - Complete the API references of WebSocket, WebSocketClient and the stream:: helpers, and the SSE reconnect rules. - Fix cookbook pages: keychain loading on every backend, received Close status, a multipart sample that trusted the client's file name, an echo sample that sent binary as text, SNI, pre-request handler scope, stop() with WebSocket handlers, and the thread pool notes. - Restore the mutex in the LLM app's Chapter 5 code.
56 lines
3.8 KiB
Markdown
56 lines
3.8 KiB
Markdown
---
|
|
title: "S11. Pre-request handlerでルート単位の認証を行う"
|
|
order: 30
|
|
status: "draft"
|
|
---
|
|
|
|
[S09. 全ルートに共通の前処理をする](../s09-pre-routing)で紹介した`set_pre_routing_handler()`はルーティングの**前**に呼ばれるので、「どのルートにマッチしたか」を知れません。ルートによって認証の有無を変えたい場合は、`set_pre_request_handler()`のほうが便利です。
|
|
|
|
## Pre-routingとの違い
|
|
|
|
| フック | 呼ばれるタイミング | ルート情報 | リクエストボディ |
|
|
| --- | --- | --- | --- |
|
|
| `set_pre_routing_handler` | ルーティングの前 | 取得できない | まだ読まれていない |
|
|
| `set_pre_request_handler` | ルーティング後、ルートハンドラの直前 | `req.matched_route`で取得可能 | まだ読まれていない |
|
|
|
|
Pre-requestハンドラなら、`req.matched_route`に「マッチしたパターン文字列」が入っているので、ルートに応じて処理を変えられます。
|
|
|
|
Pre-requestハンドラが呼ばれる時点ではボディがまだ読まれていないので、認証に失敗したリクエストなどを、(巨大かもしれない)ボディを読み込む前に拒否できます。その代わり、`req.body`やボディから解析されるフォームフィールドはこの時点では参照できません。ヘッダ・パス・クエリパラメータ・`req.matched_route`を使って判断してください。
|
|
|
|
Pre-requestハンドラが呼ばれるのは、ルートにマッチしたリクエストだけです。`set_mount_point()`で配信するファイルはルートのマッチングより前に返されるので、静的ファイルを守りたいときはPre-routingハンドラでチェックしてください。
|
|
|
|
## ルートごとに認証を切り替える
|
|
|
|
```cpp
|
|
svr.set_pre_request_handler(
|
|
[](const httplib::Request &req, httplib::Response &res) {
|
|
// /adminで始まるルートだけ認証を要求
|
|
if (req.matched_route.rfind("/admin", 0) == 0) {
|
|
auto token = req.get_header_value("Authorization");
|
|
if (!is_admin_token(token)) {
|
|
res.status = 403;
|
|
res.set_content("forbidden", "text/plain");
|
|
return httplib::Server::HandlerResponse::Handled;
|
|
}
|
|
}
|
|
return httplib::Server::HandlerResponse::Unhandled;
|
|
});
|
|
```
|
|
|
|
`matched_route`はパスパラメーターを展開する**前**のパターン文字列(例: `/admin/users/:id`)です。特定の値ではなく、ルート定義のパターンで判定できるので、IDや名前に左右されません。
|
|
|
|
`svr.WebSocket()`で登録したルートでも、Pre-requestハンドラは呼ばれます。呼ばれるのは`101 Switching Protocols`を返す前なので、`Handled`を返すとそのHTTPレスポンス(403など)がそのまま返り、WebSocketへのアップグレードは行われません。
|
|
|
|
サーバーはどの`Origin`からのハンドシェイクも受け付けます。ブラウザは別のサイトが始めたハンドシェイクにもCookieを付けて送るので、Cookieで接続を認証している場合は、`req.get_header_value("Origin")`が自分のオリジンかどうかもここで確認してください。
|
|
|
|
## 戻り値の意味
|
|
|
|
Pre-routingハンドラと同じく、`HandlerResponse`を返します。
|
|
|
|
- `Unhandled`: 通常の処理を続行(ルートハンドラが呼ばれる)
|
|
- `Handled`: ここで完了、ルートハンドラはスキップされる
|
|
|
|
## 認証情報を後続のハンドラに渡す
|
|
|
|
認証で取り出したユーザー情報などをルートハンドラに渡したいときは、`res.user_data`を使います。詳しくは[S12. `res.user_data`でハンドラ間データを渡す](../s12-user-data)を参照してください。
|