Make sure that you can compile and run core tests and read a basic example Writing your first HTTP server.
This tutorial shows how to create a custom authorization check by tokens with scopes for HTTP handlers. Required scopes are specified in static configuration file for each HTTP handler. In the tutorial the authorization data is cached in components::PostgreCache, and information of an authorized user (it's name) is passed to the HTTP handler.
Creation of tokens and user registration is out of scope of this tutorial.
Let's make a table to store users data:
Authorization data is rarely changed and often queried. Caching it would improve response times:
Cache configuration is straightforward:
auth-database:
dbconnection: 'postgresql://testsuite@localhost:15433/postgres'
blocking_task_processor: fs-task-processor
dns_resolver: async
auth-pg-cache:
pgcomponent: auth-database
update-interval: 10s
To implement an authorization checker derive from server::handlers::auth::AuthCheckerBase and override the virtual functions:
The authorization should do the following steps:
Bearer some-token
format, return 403 if it is not; CheckAuth
functions are invoked concurrently on the same instance of the class. In this sample the AuthCheckerBearer
class only reads the class data. synchronization primitives should be used if data is mutated.Authorization checkers are produced by authorization factories derived from server::handlers::auth::AuthCheckerFactoryBase:
Factories work with component system and parse handler-specific authorization configs:
Each factory should be registered at the beginning of the main()
function via server::handlers::auth::RegisterAuthCheckerFactory function call:
That factory is invoked on each HTTP handler with the matching authorization type:
handler-hello:
path: /v1/hello
task_processor: main-task-processor
method: GET
auth: # Authorization config for this handler
types:
- bearer # Authorization type that was specified in main()
scopes: # Required user scopes for that handler
- read
- hello
Data that was set by authorization checker could be retrieved by handler from server::request::RequestContext:
Aside from calling server::handlers::auth::RegisterAuthCheckerFactory for authorization factory registration, the main()
function should also construct the component list and start the daemon:
To build the sample, execute the following build steps at the userver root directory:
The sample could be started by running make start-userver-samples-postgres_auth
. The command would invoke testsuite start target that sets proper paths in the configuration files, prepares and starts the DB, and starts the service.
To start the service manually start the DB server and run ./samples/postgres_service/userver-samples-postgres_auth -c </path/to/static_config.yaml>
.
Now you can send a request to your service from another terminal:
$ curl 'localhost:8080/v1/hello' -i
HTTP/1.1 401 Unauthorized
Date: Wed, 21 Dec 2022 13:04:17 UTC
Content-Type: text/html
X-YaRequestId: dbc9dbaa3fc04ce8a86b27a1aa582cd6
X-YaSpanId: aa573144f2312714
X-YaTraceId: 4dfb9e852e07473c9d57a8eb520e7965
Server: userver/2.0 (20221221124812; rv:unknown)
Connection: keep-alive
Content-Length: 28
Empty 'Authorization' header
$ curl -H 'Authorization: Bearer SOME_WRONG_USER_TOKEN' 'localhost:8080/v1/hello' -i
HTTP/1.1 403 Forbidden
Date: Wed, 21 Dec 2022 13:06:06 UTC
Content-Type: text/html
X-YaRequestId: 6e39f3bf27324aa3acb01a30b9653b2d
X-YaTraceId: e5d38ab53b3f495a9b97279a731f5fde
X-YaSpanId: e64b939c37035d88
Server: userver/2.0 (20221221124812; rv:unknown)
Connection: keep-alive
Content-Length: 0
Functional tests for the service could be implemented using the testsuite. To do that you have to:
See the full example: