Add some functionality
new handler for me
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
#include "repo/user_repository.hpp"
|
||||
#include "security/password_hasher.hpp"
|
||||
#include "security/session_token_service.hpp"
|
||||
#include "service/auto_service.hpp"
|
||||
#include "service/auth_service.hpp"
|
||||
#include "util/time_utils.hpp"
|
||||
#include "util/validation.hpp"
|
||||
|
||||
@@ -52,6 +52,14 @@ int Application::run() const {
|
||||
HealthController health_controller;
|
||||
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(
|
||||
"/login",
|
||||
[&auth_controller](const drogon::HttpRequestPtr &req,
|
||||
|
||||
@@ -1,13 +1,47 @@
|
||||
#include "http/controllers/auth_controller.hpp"
|
||||
|
||||
#include "service/auth_errors.hpp"
|
||||
#include "service/auto_service.hpp"
|
||||
#include "service/auth_service.hpp"
|
||||
|
||||
#include <drogon/drogon.h>
|
||||
#include <json/json.h>
|
||||
|
||||
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,
|
||||
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"]["message"] = "Expected JSON body with email and password";
|
||||
|
||||
auto responce = drogon::HttpResponse::newHttpJsonResponse(error);
|
||||
responce->setStatusCode(drogon::k400BadRequest);
|
||||
callback(responce);
|
||||
auto response = drogon::HttpResponse::newHttpJsonResponse(error);
|
||||
response->setStatusCode(drogon::k400BadRequest);
|
||||
callback(response);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const auto result = auto_servise_.login(LoginCommand{
|
||||
const auto result = auth_servise_.login(LoginCommand{
|
||||
.email = (*json)["email"].asString(),
|
||||
.password = (*json)["password"].asString(),
|
||||
});
|
||||
@@ -91,7 +125,7 @@ void AuthController::register_user(
|
||||
}
|
||||
|
||||
try {
|
||||
const auto result = auto_servise_.register_user(RegisterCommand{
|
||||
const auto result = auth_servise_.register_user(RegisterCommand{
|
||||
.email = (*json)["email"].asString(),
|
||||
.password = (*json)["password"].asString(),
|
||||
});
|
||||
|
||||
@@ -15,10 +15,13 @@ public:
|
||||
void login(const drogon::HttpRequestPtr &req,
|
||||
std::function<void(const drogon::HttpResponsePtr &)> &&callback) const;
|
||||
|
||||
void me(const drogon::HttpRequestPtr &req,
|
||||
std::function<void(const drogon::HttpResponsePtr &)> &&callback) const;
|
||||
|
||||
private:
|
||||
bool isValidAuthJson(const std::shared_ptr<Json::Value> &req) const;
|
||||
bool isValidLoginJson(const std::shared_ptr<Json::Value> &req) const;
|
||||
|
||||
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 };
|
||||
}
|
||||
|
||||
std::string SessionTokenService::hash_token(std::string_view raw_token) const {
|
||||
return sha256_hex(std::string{ raw_token });
|
||||
}
|
||||
|
||||
std::string SessionTokenService::generate_random_token() {
|
||||
unsigned char buffer[kTokenSizeBytes];
|
||||
if(RAND_bytes(buffer, sizeof(buffer)) != 1) {
|
||||
|
||||
@@ -9,6 +9,8 @@ class SessionTokenService {
|
||||
public:
|
||||
SessionTokenPair generate() const;
|
||||
|
||||
std::string hash_token(std::string_view raw_token) const;
|
||||
|
||||
private:
|
||||
static std::string generate_random_token();
|
||||
static std::string sha256_hex(const std::string &input);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "util/time_utils.hpp"
|
||||
#include "util/validation.hpp"
|
||||
|
||||
#include <service/auto_service.hpp>
|
||||
#include <service/auth_service.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
const auto email = normalize_email(command.email);
|
||||
// validateData(email, command.password);
|
||||
|
||||
@@ -27,6 +27,11 @@ struct RegisterResult {
|
||||
std::string email;
|
||||
};
|
||||
|
||||
struct CurrentUserResult {
|
||||
std::int64_t id{};
|
||||
std::string email;
|
||||
};
|
||||
|
||||
class AuthService {
|
||||
public:
|
||||
AuthService(UserRepository &users, SessionRepository &session, PasswordHasher &password_hasher,
|
||||
@@ -35,6 +40,8 @@ public:
|
||||
RegisterResult register_user(const RegisterCommand &command) const;
|
||||
LoginResult login(const LoginCommand &loginCommand) const;
|
||||
|
||||
CurrentUserResult authenticate_by_session_token(std::string_view raw_token) const;
|
||||
|
||||
private:
|
||||
void validateData(std::string_view email, std::string_view password) const;
|
||||
|
||||
Reference in New Issue
Block a user