Force update cache for auth via postgresql
Hi, I watched into documentation at userver.tech. There was an example Custom Authorization/Authentication via PostgreSQL "Creation of tokens and user registration is out of scope of this tutorial."
I made a custom basic registration:
hpp
namespace rl::handlers
{
class Register final : public userver::server::handlers::HttpHandlerBase
{
public:
Register( const userver::components::ComponentConfig& config,
const userver::components::ComponentContext& context );
public:
static constexpr std::string_view kName = "handler-register";
using HttpHandlerBase::HttpHandlerBase;
std::string
HandleRequestThrow( const userver::server::http::HttpRequest& request,
userver::server::request::RequestContext& request_context ) const override;
private:
userver::storages::postgres::ClusterPtr pg_cluster_;
};
} // namespace rl::handlers
cpp
namespace rl::handlers
{
Register::Register( const userver::components::ComponentConfig& config,
const userver::components::ComponentContext& context )
: userver::server::handlers::HttpHandlerBase{ config, context }
, pg_cluster_{
context.FindComponent< userver::components::Postgres >( "auth-database" ).GetCluster()
}
{
}
std::string
Register::HandleRequestThrow( const userver::server::http::HttpRequest& request,
userver::server::request::RequestContext& ) const
{
const auto request_body{ userver::formats::json::FromString( request.RequestBody() ) };
const auto& username { request_body["username"].As<std::string>() };
const auto& password { request_body[ "password" ].As< std::string >() };
const auto& mail { request_body["mail"].As<std::string>() };
const auto token = jwt::create()
.set_type( "JWT" )
.set_id( "rsa-create-example" )
.set_issued_now()
.set_expires_in( std::chrono::seconds{ 36000 } )
.set_payload_claim( "sample", jwt::claim( std::string{ "test" } ) )
.sign( jwt::algorithm::hs256( "secret" ) );
auto trx { pg_cluster_->Begin("sample_transaction_insert_key_value", userver::storages::postgres::ClusterHostType::kMaster, {})};
const auto pg_query_register = "INSERT INTO auth_schema.users(username, mail, password) "
"VALUES ($1, $2, $3) "
"RETURNING id;";
auto trx_result{ pg_cluster_->Execute(
userver::storages::postgres::ClusterHostType::kSlave,
pg_query_register,
username,
mail,
password ) };
if ( trx_result.IsEmpty() )
{
request.SetResponseStatus( userver::server::http::HttpStatus::kBadRequest );
return {};
}
const auto user_id { trx_result.AsSingleRow<int>() };
const auto pg_query_save_token{ "INSERT INTO auth_schema.tokens(token, user_id) "
"VALUES ($1, $2);" };
trx_result = pg_cluster_->Execute(
userver::storages::postgres::ClusterHostType::kMaster,
pg_query_save_token,
token,
user_id);
trx.Commit();
userver::formats::json::ValueBuilder response;
response[ "token" ] = token;
return userver::formats::json::ToString( response.ExtractValue() );
}
} // namespace rl::handlers
Cache for auth from example:
namespace rl::pg::auth
{
struct UserDbInfo
{
userver::server::auth::UserAuthInfo::Ticket token;
std::int64_t user_id;
std::vector< std::string > scopes;
};
struct AuthCachePolicy
{
static constexpr std::string_view kName = "auth-pg-cache";
using ValueType = UserDbInfo;
static constexpr auto kKeyMember = &UserDbInfo::token;
static constexpr const char* kQuery =
"SELECT token, user_id, scopes, name FROM auth_schema.tokens";
static constexpr const char* kUpdatedField = "updated";
using UpdatedFieldType = userver::storages::postgres::TimePointTz;
// Using crypto::algorithm::StringsEqualConstTimeComparator to avoid timing
// attack at find(token).
using CacheContainer =
std::unordered_map< userver::server::auth::UserAuthInfo::Ticket,
UserDbInfo,
std::hash< userver::server::auth::UserAuthInfo::Ticket >,
userver::crypto::algorithm::StringsEqualConstTimeComparator >;
};
using AuthCache = userver::components::PostgreCache< AuthCachePolicy >;
} // namespace rl::pg::auth
Is it possible to force updating cache? Or it is ok to wait until it updates itself each 10 seconds?
maybe you look for this https://userver.tech/da/df8/classcache_1_1CacheUpdateTrait.html#a317ae9796c9108002c4efd1227882cf5
@h1laryz it's a matter of configuration. You can configure the server to do updates every second or every half a second by providing a required update_interval https://userver.tech/d5/d2d/md_en_2userver_2caches.html#autotoc_md239
Not that such action will increase CPU consumption, so choose according to your needs
If you wish to force manual update you can use UpdateSyncDebug() https://userver.tech/da/df8/classcache_1_1CacheUpdateTrait.html#a7ed99a01e30d17df235831480156268e. However that is almost always a bad idea to use that function outside of tests. Such solution does not scale well, because the update happens only on local instance, and other instances of the service get the update after update_interval