Add some functionality
new handler for me
This commit is contained in:
@@ -8,7 +8,7 @@
|
|||||||
#include "repo/user_repository.hpp"
|
#include "repo/user_repository.hpp"
|
||||||
#include "security/password_hasher.hpp"
|
#include "security/password_hasher.hpp"
|
||||||
#include "security/session_token_service.hpp"
|
#include "security/session_token_service.hpp"
|
||||||
#include "service/auto_service.hpp"
|
#include "service/auth_service.hpp"
|
||||||
#include "util/time_utils.hpp"
|
#include "util/time_utils.hpp"
|
||||||
#include "util/validation.hpp"
|
#include "util/validation.hpp"
|
||||||
|
|
||||||
@@ -52,6 +52,14 @@ int Application::run() const {
|
|||||||
HealthController health_controller;
|
HealthController health_controller;
|
||||||
AuthController auth_controller(auth_service);
|
AuthController auth_controller(auth_service);
|
||||||
|
|
||||||
|
drogon::app().registerHandler(
|
||||||
|
"/me",
|
||||||
|
[&auth_controller](const drogon::HttpRequestPtr &req,
|
||||||
|
std::function<void(const drogon::HttpResponsePtr &)> &&callback) {
|
||||||
|
auth_controller.me(req, std::move(callback));
|
||||||
|
},
|
||||||
|
{ drogon::Get });
|
||||||
|
|
||||||
drogon::app().registerHandler(
|
drogon::app().registerHandler(
|
||||||
"/login",
|
"/login",
|
||||||
[&auth_controller](const drogon::HttpRequestPtr &req,
|
[&auth_controller](const drogon::HttpRequestPtr &req,
|
||||||
|
|||||||
@@ -1,13 +1,47 @@
|
|||||||
#include "http/controllers/auth_controller.hpp"
|
#include "http/controllers/auth_controller.hpp"
|
||||||
|
|
||||||
#include "service/auth_errors.hpp"
|
#include "service/auth_errors.hpp"
|
||||||
#include "service/auto_service.hpp"
|
#include "service/auth_service.hpp"
|
||||||
|
|
||||||
#include <drogon/drogon.h>
|
#include <drogon/drogon.h>
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
|
|
||||||
AuthController::AuthController(AuthService &auth_service)
|
AuthController::AuthController(AuthService &auth_service)
|
||||||
: auto_servise_(auth_service) {}
|
: auth_servise_(auth_service) {}
|
||||||
|
|
||||||
|
void AuthController::me(const drogon::HttpRequestPtr &req,
|
||||||
|
std::function<void(const drogon::HttpResponsePtr &)> &&callback) const {
|
||||||
|
const auto session_token = req->getCookie("sid");
|
||||||
|
|
||||||
|
try {
|
||||||
|
const auto user = auth_servise_.authenticate_by_session_token(session_token);
|
||||||
|
|
||||||
|
Json::Value body;
|
||||||
|
body["id"] = static_cast<Json::Int64>(user.id);
|
||||||
|
body["email"] = user.email;
|
||||||
|
|
||||||
|
auto response = drogon::HttpResponse::newHttpJsonResponse(body);
|
||||||
|
response->setStatusCode(drogon::k200OK);
|
||||||
|
callback(response);
|
||||||
|
} catch(const UnauthorizedError &ex) {
|
||||||
|
Json::Value error;
|
||||||
|
error["error"]["code"] = "unauthorized";
|
||||||
|
error["error"]["message"] = ex.what();
|
||||||
|
|
||||||
|
auto response = drogon::HttpResponse::newHttpJsonResponse(error);
|
||||||
|
response->setStatusCode(drogon::k401Unauthorized);
|
||||||
|
callback(response);
|
||||||
|
} catch(const std::exception &e) {
|
||||||
|
Json::Value error;
|
||||||
|
error["error"]["code"] = "internal_error";
|
||||||
|
error["error"]["message"] = "Internal server error";
|
||||||
|
|
||||||
|
auto response = drogon::HttpResponse::newHttpJsonResponse(error);
|
||||||
|
response->setStatusCode(drogon::k500InternalServerError);
|
||||||
|
callback(response);
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AuthController::login(const drogon::HttpRequestPtr &req,
|
void AuthController::login(const drogon::HttpRequestPtr &req,
|
||||||
std::function<void(const drogon::HttpResponsePtr &)> &&callback) const {
|
std::function<void(const drogon::HttpResponsePtr &)> &&callback) const {
|
||||||
@@ -17,13 +51,13 @@ void AuthController::login(const drogon::HttpRequestPtr
|
|||||||
error["error"]["code"] = "invalid_request";
|
error["error"]["code"] = "invalid_request";
|
||||||
error["error"]["message"] = "Expected JSON body with email and password";
|
error["error"]["message"] = "Expected JSON body with email and password";
|
||||||
|
|
||||||
auto responce = drogon::HttpResponse::newHttpJsonResponse(error);
|
auto response = drogon::HttpResponse::newHttpJsonResponse(error);
|
||||||
responce->setStatusCode(drogon::k400BadRequest);
|
response->setStatusCode(drogon::k400BadRequest);
|
||||||
callback(responce);
|
callback(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const auto result = auto_servise_.login(LoginCommand{
|
const auto result = auth_servise_.login(LoginCommand{
|
||||||
.email = (*json)["email"].asString(),
|
.email = (*json)["email"].asString(),
|
||||||
.password = (*json)["password"].asString(),
|
.password = (*json)["password"].asString(),
|
||||||
});
|
});
|
||||||
@@ -91,7 +125,7 @@ void AuthController::register_user(
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const auto result = auto_servise_.register_user(RegisterCommand{
|
const auto result = auth_servise_.register_user(RegisterCommand{
|
||||||
.email = (*json)["email"].asString(),
|
.email = (*json)["email"].asString(),
|
||||||
.password = (*json)["password"].asString(),
|
.password = (*json)["password"].asString(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -15,10 +15,13 @@ public:
|
|||||||
void login(const drogon::HttpRequestPtr &req,
|
void login(const drogon::HttpRequestPtr &req,
|
||||||
std::function<void(const drogon::HttpResponsePtr &)> &&callback) const;
|
std::function<void(const drogon::HttpResponsePtr &)> &&callback) const;
|
||||||
|
|
||||||
|
void me(const drogon::HttpRequestPtr &req,
|
||||||
|
std::function<void(const drogon::HttpResponsePtr &)> &&callback) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isValidAuthJson(const std::shared_ptr<Json::Value> &req) const;
|
bool isValidAuthJson(const std::shared_ptr<Json::Value> &req) const;
|
||||||
bool isValidLoginJson(const std::shared_ptr<Json::Value> &req) const;
|
bool isValidLoginJson(const std::shared_ptr<Json::Value> &req) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AuthService &auto_servise_;
|
AuthService &auth_servise_;
|
||||||
};
|
};
|
||||||
@@ -26,6 +26,10 @@ SessionTokenPair SessionTokenService::generate() const {
|
|||||||
return SessionTokenPair{ .raw_token = raw_token, .token_hash = token_hash };
|
return SessionTokenPair{ .raw_token = raw_token, .token_hash = token_hash };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string SessionTokenService::hash_token(std::string_view raw_token) const {
|
||||||
|
return sha256_hex(std::string{ raw_token });
|
||||||
|
}
|
||||||
|
|
||||||
std::string SessionTokenService::generate_random_token() {
|
std::string SessionTokenService::generate_random_token() {
|
||||||
unsigned char buffer[kTokenSizeBytes];
|
unsigned char buffer[kTokenSizeBytes];
|
||||||
if(RAND_bytes(buffer, sizeof(buffer)) != 1) {
|
if(RAND_bytes(buffer, sizeof(buffer)) != 1) {
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ class SessionTokenService {
|
|||||||
public:
|
public:
|
||||||
SessionTokenPair generate() const;
|
SessionTokenPair generate() const;
|
||||||
|
|
||||||
|
std::string hash_token(std::string_view raw_token) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::string generate_random_token();
|
static std::string generate_random_token();
|
||||||
static std::string sha256_hex(const std::string &input);
|
static std::string sha256_hex(const std::string &input);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include "util/time_utils.hpp"
|
#include "util/time_utils.hpp"
|
||||||
#include "util/validation.hpp"
|
#include "util/validation.hpp"
|
||||||
|
|
||||||
#include <service/auto_service.hpp>
|
#include <service/auth_service.hpp>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
AuthService::AuthService(UserRepository &users, SessionRepository &session,
|
AuthService::AuthService(UserRepository &users, SessionRepository &session,
|
||||||
@@ -32,6 +32,40 @@ void AuthService::validateData(std::string_view email, std::string_view password
|
|||||||
throw EmailAlreadyExistsError("Email already exists");
|
throw EmailAlreadyExistsError("Email already exists");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CurrentUserResult AuthService::authenticate_by_session_token(std::string_view raw_token) const {
|
||||||
|
if(raw_token.empty()) {
|
||||||
|
throw UnauthorizedError("Unauthorized");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto token_hash = token_service_.hash_token(raw_token);
|
||||||
|
|
||||||
|
const auto session = sessions_.find_by_token_hash(token_hash);
|
||||||
|
|
||||||
|
if(!session.has_value()) {
|
||||||
|
throw UnauthorizedError("Unauthorized");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(session->revoked_at.has_value()) {
|
||||||
|
throw UnauthorizedError("Unauthorized");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto now = now_utc_iso8601();
|
||||||
|
if(session->expires_at <= now) {
|
||||||
|
throw UnauthorizedError("Session expired");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto user = users_.find_by_id(session->user_id);
|
||||||
|
if(!user.has_value() || !user->is_active) {
|
||||||
|
throw UnauthorizedError("Unauthorized");
|
||||||
|
}
|
||||||
|
|
||||||
|
return CurrentUserResult{
|
||||||
|
.id = user->id,
|
||||||
|
.email = user->email,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
LoginResult AuthService::login(const LoginCommand &command) const {
|
LoginResult AuthService::login(const LoginCommand &command) const {
|
||||||
const auto email = normalize_email(command.email);
|
const auto email = normalize_email(command.email);
|
||||||
// validateData(email, command.password);
|
// validateData(email, command.password);
|
||||||
|
|||||||
@@ -27,6 +27,11 @@ struct RegisterResult {
|
|||||||
std::string email;
|
std::string email;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CurrentUserResult {
|
||||||
|
std::int64_t id{};
|
||||||
|
std::string email;
|
||||||
|
};
|
||||||
|
|
||||||
class AuthService {
|
class AuthService {
|
||||||
public:
|
public:
|
||||||
AuthService(UserRepository &users, SessionRepository &session, PasswordHasher &password_hasher,
|
AuthService(UserRepository &users, SessionRepository &session, PasswordHasher &password_hasher,
|
||||||
@@ -35,6 +40,8 @@ public:
|
|||||||
RegisterResult register_user(const RegisterCommand &command) const;
|
RegisterResult register_user(const RegisterCommand &command) const;
|
||||||
LoginResult login(const LoginCommand &loginCommand) const;
|
LoginResult login(const LoginCommand &loginCommand) const;
|
||||||
|
|
||||||
|
CurrentUserResult authenticate_by_session_token(std::string_view raw_token) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void validateData(std::string_view email, std::string_view password) const;
|
void validateData(std::string_view email, std::string_view password) const;
|
||||||
|
|
||||||
Reference in New Issue
Block a user