Add token validation filter based on token signature and expiration date

- changed login request from GET to POST
- implement json body conversion to DTO objects
- set `user_id` and `role` attributes for HttpRequest inside filter
This commit is contained in:
2025-06-14 16:35:18 +04:00
parent 16c7e94345
commit 6df4896628
14 changed files with 285 additions and 64 deletions

View File

@@ -1,23 +1,99 @@
#include "UserManager.h"
#include <chrono>
#include <vector>
#include <drogon/utils/Utilities.h>
#include <jwt-cpp/jwt.h>
#include <jwt-cpp/traits/nlohmann-json/defaults.h>
#include "dependency_injection/DependencyContainer.h"
#include "models/User.h"
#include "services/encryption/PasswordEncryptor.h"
std::string PUBLIC_KEY{
R"(-----BEGIN PUBLIC KEY-----
MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgGlyZf3ilQWS862UM0wPL9t+B/La
E4QiLOWULVmiHvtg6ly5erX4LeKX9og0LYgdUyialjPRElutRq1dTEJ4x9kgDkT4
o+hwcem+OHKkdbIfGSIdrI1SzWPYq8F9JjL9elPghD8Rul1US+2HWyrJkw3YiAjU
gmZ8mUpu5Hkq+LjzAgMBAAE=
-----END PUBLIC KEY-----)"
};
std::string PRIVATE_KEY{
R"(-----BEGIN RSA PRIVATE KEY-----
MIICWgIBAAKBgGlyZf3ilQWS862UM0wPL9t+B/LaE4QiLOWULVmiHvtg6ly5erX4
LeKX9og0LYgdUyialjPRElutRq1dTEJ4x9kgDkT4o+hwcem+OHKkdbIfGSIdrI1S
zWPYq8F9JjL9elPghD8Rul1US+2HWyrJkw3YiAjUgmZ8mUpu5Hkq+LjzAgMBAAEC
gYATCsimV5OnxQjiUMAOvTNcRN80mPMrSmynLOIfrKpBpRfNlOU3FVFb+StZH2sV
iI4q5/e19cyF5726sv2Bh4Q3Uob6eJZfpcReScUtbhFLhikCSTvWf6g+6ebCBF9m
HoXQBvJhthRo+9BSoweZjxNZirxO1DaqbrxIdufpBJL9aQJBAL/iyzb7mQ/oq8/j
BcVnPlOBK6R3q5ZcynJTgyLMTldAwTB4WZrUPBWt51WUL7LoZhMtQIGNaqApSwyp
ehaRKscCQQCMre5E5QXDvAITYIoGNs1x5qVUzKCYXYIv0hdko21V9GLNaYWLL5ux
BAZsvNLBE2DMbl4mJiL198qJItYk0nR1AkAIXjGSgkJYiUME29eiljAHoDhxAa7/
7af+eFndqJ85+t7x6C2wLNU59M2D0+SIns3kxDJt8+bUeTiGotVqKoZ9AkAELNFK
eCWQpo7FNnNCNfQo8jhr6NrHStcnRivtj7AaAfPAtuYAuHv9Z+os5fm3QzT3PDtN
FIqrFByNr1v9ocVVAkAWvQ4q4Mkw8u/zCAuPiK9NJn377nc4bENQkcn6ZJ4dbMgt
yV8QswCTqtfaXKyOEs46WNYhEtMahiLPeL7V23Mr
-----END RSA PRIVATE KEY-----)"
};
UserManager::UserManager()
{
m_logger = DependencyContainer::Resolve<spdlog::logger>();
m_passwordEncryptor = DependencyContainer::Resolve<PasswordEncryptor>();
}
bool UserManager::validateCredentials(const User& userData, std::string&& rawPassword)
{
auto hashedPassword = hashPassword(std::move(rawPassword));
auto base64Hash = drogon::utils::base64Encode(hashedPassword.data(), hashedPassword.size());
return base64Hash == userData.passwordHash;
return hashedPassword == userData.passwordHash;
}
std::vector<uint8_t> UserManager::hashPassword(std::string&& rawPassword)
bool UserManager::validateRegisterData(const RegisterRequestDto& registerData)
{
return m_passwordEncryptor->encryptPassword(std::move(rawPassword));
return true;
}
std::string UserManager::generateToken(const User& userData)
{
return jwt::create()
.set_type("JWT")
.set_payload_claim("user_id", jwt::claim(userData.id))
.set_payload_claim("role", jwt::claim(userData.role))
.set_expires_in(std::chrono::seconds{ 3600 })
.sign(jwt::algorithm::rs256{ "", PRIVATE_KEY });
}
std::string UserManager::hashPassword(std::string&& rawPassword)
{
auto hashData = m_passwordEncryptor->encryptPassword(std::move(rawPassword));
return drogon::utils::base64Encode(hashData.data(), hashData.size());
}
bool UserManager::validateToken(const std::string& token)
{
try
{
auto decoded = jwt::decode(token);
auto verifier = jwt::verify()
.allow_algorithm(jwt::algorithm::rs256{ PUBLIC_KEY, "" });
verifier.verify(decoded);
}
catch (const jwt::error::token_verification_exception& ex)
{
m_logger->info("Failed to validate token: {}", ex.what());
return false;
}
return true;
}
std::string UserManager::getPayloadFromToken(const std::string& token)
{
try
{
auto decoded = jwt::decode(token);
return decoded.get_payload();
}
catch (const std::exception& ex)
{ }
}