mirror of
https://github.com/Relintai/rcpp_framework.git
synced 2024-11-10 00:52:11 +01:00
Implemented middleware handling. Also converted middleware handlers to the new stystem.
This commit is contained in:
parent
ef18e705f4
commit
ec2eabacc1
@ -7,7 +7,7 @@ bool Middleware::on_before_handle_request_main(Request *request) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Middleware::Middleware() {
|
||||
Middleware::Middleware() : Reference() {
|
||||
}
|
||||
|
||||
Middleware::~Middleware() {
|
||||
|
@ -152,7 +152,7 @@ void SessionManager::load_sessions() {
|
||||
|
||||
b->select("id, session_id");
|
||||
b->from(_table_name);
|
||||
//b->print();
|
||||
// b->print();
|
||||
Ref<QueryResult> r = b->run();
|
||||
|
||||
while (r->next_row()) {
|
||||
@ -171,7 +171,7 @@ void SessionManager::load_sessions() {
|
||||
|
||||
b->select("session_db_id, key, value");
|
||||
b->from(_data_table_name);
|
||||
//b->print();
|
||||
// b->print();
|
||||
r = b->run();
|
||||
|
||||
while (r->next_row()) {
|
||||
@ -213,7 +213,7 @@ void SessionManager::clear() {
|
||||
}
|
||||
|
||||
String SessionManager::generate_session_id(const String &base) {
|
||||
//todo make something simpler / better
|
||||
// todo make something simpler / better
|
||||
|
||||
SHA256 *h = SHA256::get();
|
||||
String sid = base;
|
||||
@ -229,26 +229,6 @@ String SessionManager::generate_session_id(const String &base) {
|
||||
return sid;
|
||||
}
|
||||
|
||||
void SessionManager::session_setup_middleware(Object *instance, Request *request) {
|
||||
const String sid = request->get_cookie("session_id");
|
||||
|
||||
if (sid == "") {
|
||||
//You could create a session here if you want to always assign sessions to visitors.
|
||||
//Example code:
|
||||
//HTTPSession *session = SessionManager::get_singleton()->create_session();
|
||||
//request->session = session;
|
||||
//request->add_cookie(::Cookie("session_id", session->session_id));
|
||||
|
||||
request->next_stage();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
request->session = SessionManager::get_singleton()->get_session(sid);
|
||||
|
||||
request->next_stage();
|
||||
}
|
||||
|
||||
void SessionManager::migrate() {
|
||||
drop_table();
|
||||
create_table();
|
||||
@ -262,7 +242,7 @@ void SessionManager::create_table() {
|
||||
tb->varchar("session_id", 100)->next_row();
|
||||
tb->primary_key("id");
|
||||
tb->ccreate_table();
|
||||
//tb->print();
|
||||
// tb->print();
|
||||
tb->run_query();
|
||||
|
||||
tb->result = "";
|
||||
@ -274,7 +254,7 @@ void SessionManager::create_table() {
|
||||
tb->foreign_key("session_db_id");
|
||||
tb->references(_table_name, "id");
|
||||
tb->ccreate_table();
|
||||
//tb->print();
|
||||
// tb->print();
|
||||
tb->run_query();
|
||||
}
|
||||
void SessionManager::drop_table() {
|
||||
@ -310,4 +290,27 @@ SessionManager::~SessionManager() {
|
||||
|
||||
SessionManager *SessionManager::_self = nullptr;
|
||||
String SessionManager::_table_name = "sessions";
|
||||
String SessionManager::_data_table_name = "session_data";
|
||||
String SessionManager::_data_table_name = "session_data";
|
||||
|
||||
bool SessionSetupMiddleware::on_before_handle_request_main(Request *request) {
|
||||
const String sid = request->get_cookie("session_id");
|
||||
|
||||
if (sid == "") {
|
||||
// You could create a session here if you want to always assign sessions to visitors.
|
||||
// Example code:
|
||||
// HTTPSession *session = SessionManager::get_singleton()->create_session();
|
||||
// request->session = session;
|
||||
// request->add_cookie(::Cookie("session_id", session->session_id));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
request->session = SessionManager::get_singleton()->get_session(sid);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SessionSetupMiddleware::SessionSetupMiddleware() {
|
||||
}
|
||||
SessionSetupMiddleware::~SessionSetupMiddleware() {
|
||||
}
|
||||
|
@ -3,11 +3,12 @@
|
||||
|
||||
#include "core/string.h"
|
||||
#include "core/containers/vector.h"
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
|
||||
#include "core/object.h"
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include "middleware.h"
|
||||
|
||||
class HTTPSession;
|
||||
class Request;
|
||||
@ -29,8 +30,6 @@ public:
|
||||
|
||||
virtual String generate_session_id(const String &base = "");
|
||||
|
||||
static void session_setup_middleware(Object *instance, Request *request);
|
||||
|
||||
virtual void migrate();
|
||||
virtual void create_table();
|
||||
virtual void drop_table();
|
||||
@ -51,4 +50,15 @@ protected:
|
||||
static String _data_table_name;
|
||||
};
|
||||
|
||||
class SessionSetupMiddleware : public Middleware {
|
||||
RCPP_OBJECT(SessionSetupMiddleware, Middleware);
|
||||
|
||||
public:
|
||||
//returnring true means handled, false means continue
|
||||
bool on_before_handle_request_main(Request *request);
|
||||
|
||||
SessionSetupMiddleware();
|
||||
~SessionSetupMiddleware();
|
||||
};
|
||||
|
||||
#endif
|
@ -22,54 +22,21 @@ void WebRoot::setup_routes() {
|
||||
}
|
||||
|
||||
void WebRoot::setup_middleware() {
|
||||
// If you want sessions add this to your inherited class. Should probably be the first one.
|
||||
// middlewares.push_back(HandlerInstance(::SessionManager::session_setup_middleware));
|
||||
// Middlewares get processed in the order they are in the _middlewares array
|
||||
|
||||
middlewares.push_back(HandlerInstance([this](Object *instance, Request *request) { this->default_routing_middleware(instance, request); }));
|
||||
}
|
||||
// If you want sessions add this to your inherited class.
|
||||
// _middlewares.push_back(Ref<SessionSetupMiddleware>(new SessionSetupMiddleware()));
|
||||
|
||||
void WebRoot::default_routing_middleware(Object *instance, Request *request) {
|
||||
// handle default phase 1
|
||||
std::string path = request->get_path_full();
|
||||
// This one looks up users based on sessions
|
||||
// _middlewares.push_back(Ref<UserSessionSetupMiddleware>(new UserSessionSetupMiddleware()));
|
||||
|
||||
if (FileCache::get_singleton()->wwwroot_has_file(path)) {
|
||||
send_file(path, request);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// call parent handle default
|
||||
|
||||
// from this this will be handled by web router node by default
|
||||
HandlerInstance handler_data;
|
||||
|
||||
// std::function<void(Object *, Request *)> func;
|
||||
|
||||
// if (path == "/") {
|
||||
if (request->get_path_segment_count() == 0) {
|
||||
// quick shortcut
|
||||
handler_data = index_func;
|
||||
} else {
|
||||
const std::string main_route = request->get_current_path_segment();
|
||||
|
||||
handler_data = main_route_map[main_route];
|
||||
|
||||
request->push_path();
|
||||
}
|
||||
|
||||
if (!handler_data.handler_func) {
|
||||
send_error(404, request);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
request->handler_instance = handler_data;
|
||||
request->next_stage();
|
||||
// Same as the previous, but if you want the RBAC system to work use one of these
|
||||
// _middlewares.push_back(Ref<RBACUserSessionSetupMiddleware>(new RBACUserSessionSetupMiddleware()));
|
||||
// _middlewares.push_back(Ref<RBACDefaultUserSessionSetupMiddleware>(new RBACDefaultUserSessionSetupMiddleware()));
|
||||
}
|
||||
|
||||
void WebRoot::default_fallback_error_handler(Request *request, int error_code) {
|
||||
request->compiled_body = default_generic_error_body;
|
||||
|
||||
request->send();
|
||||
}
|
||||
|
||||
@ -79,9 +46,12 @@ void WebRoot::default_404_error_handler(Request *request, int error_code) {
|
||||
}
|
||||
|
||||
void WebRoot::handle_request_main(Request *request) {
|
||||
// request->middleware_stack = &middlewares;
|
||||
// note that middlewares handle the routing -> WebRoot::default_routing_middleware by default
|
||||
// request->next_stage();
|
||||
for (int i = 0; i < _middlewares.size(); ++i) {
|
||||
if (_middlewares[i]->on_before_handle_request_main(request)) {
|
||||
//handled
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// handle files first
|
||||
if (try_send_wwwroot_file(request)) {
|
||||
|
@ -1,30 +1,28 @@
|
||||
#ifndef WEB_ROOT_H
|
||||
#define WEB_ROOT_H
|
||||
|
||||
#include "web_router_node.h"
|
||||
#include "core/containers/vector.h"
|
||||
#include "mutex"
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "mutex"
|
||||
#include "web_router_node.h"
|
||||
|
||||
#include "handler_instance.h"
|
||||
#include "middleware.h"
|
||||
|
||||
class Request;
|
||||
|
||||
//Middleware turn into a class (reference)
|
||||
//add them to a folder
|
||||
//method should return bool -> true to continue, false if done
|
||||
// FileCache -> set up, for this webroot, don't use singleton
|
||||
|
||||
//FileCache -> set up, for this webroot, don't use singleton
|
||||
// clean up unused things here
|
||||
// remove handler instances!
|
||||
|
||||
//clean up unused things here
|
||||
//remove handler instances!
|
||||
// Update the rest of the modules to the new systems
|
||||
|
||||
//Update the rest of the modules to the new systems
|
||||
|
||||
//remove middleware stack from request
|
||||
// remove middleware stack from request
|
||||
|
||||
class WebRoot : public WebRouterNode {
|
||||
RCPP_OBJECT(WebRoot, WebRouterNode);
|
||||
@ -63,6 +61,8 @@ public:
|
||||
std::map<std::string, HandlerInstance> main_route_map;
|
||||
std::vector<HandlerInstance> middlewares;
|
||||
|
||||
Vector<Ref<Middleware> > _middlewares;
|
||||
|
||||
std::map<int, std::function<void(Request *, int)> > error_handler_map;
|
||||
std::function<void(Request *, int)> default_error_handler_func;
|
||||
|
||||
|
@ -7,81 +7,6 @@
|
||||
#include "modules/rbac/rbac_default_permissions.h"
|
||||
#include "rbac_user.h"
|
||||
|
||||
void RBACUserController::rbac_user_session_setup_middleware(Object *instance, Request *request) {
|
||||
if (request->session) {
|
||||
int user_id = request->session->get_int("user_id");
|
||||
|
||||
if (user_id != 0) {
|
||||
|
||||
Ref<RBACUser> u = UserController::get_singleton()->db_get_user(user_id);
|
||||
|
||||
if (u.is_valid()) {
|
||||
request->reference_data["user"] = u;
|
||||
} else {
|
||||
// log
|
||||
request->session->remove_int("user_id");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
request->next_stage();
|
||||
}
|
||||
|
||||
void RBACUserController::rbac_default_user_session_middleware(Object *instance, Request *request) {
|
||||
// note: add a new file handler middleware func, so basic file handling is easy to set up before this
|
||||
|
||||
Ref<RBACRank> rank;
|
||||
|
||||
if (request->session) {
|
||||
int user_id = request->session->get_int("user_id");
|
||||
|
||||
if (user_id != 0) {
|
||||
|
||||
Ref<RBACUser> u = UserController::get_singleton()->db_get_user(user_id);
|
||||
|
||||
if (u.is_valid()) {
|
||||
rank = u->rbac_rank;
|
||||
|
||||
request->reference_data["user"] = u;
|
||||
} else {
|
||||
// log
|
||||
request->session->remove_int("user_id");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!rank.is_valid()) {
|
||||
rank = RBACController::get_singleton()->get_default_rank();
|
||||
|
||||
if (!rank.is_valid()) {
|
||||
if (RBACController::get_singleton()->continue_on_missing_default_rank()) {
|
||||
RLOG_ERR("get_default_rank() has not been set up properly!!! Continuing!");
|
||||
request->next_stage();
|
||||
} else {
|
||||
RLOG_ERR("get_default_rank() has not been set up properly!!! Sending 404!");
|
||||
request->send_error(404);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rank->has_permission(request, User::PERMISSION_READ)) {
|
||||
if (rank->has_rank_permission(RBAC_RANK_PERMISSION_USE_REDIRECT)) {
|
||||
// Note this can make the webapp prone to enumerations, if not done correctly
|
||||
// e.g. redirect from /admin, but sending 404 on a non existing uri, which does not have
|
||||
// a special rbac entry
|
||||
request->send_redirect(RBACController::get_singleton()->get_redirect_url());
|
||||
return;
|
||||
}
|
||||
|
||||
request->send_error(404);
|
||||
return;
|
||||
}
|
||||
|
||||
request->next_stage();
|
||||
}
|
||||
|
||||
Ref<User> RBACUserController::db_get_user(const int id) {
|
||||
Ref<RBACUser> u = UserController::db_get_user(id);
|
||||
|
||||
@ -131,3 +56,91 @@ RBACUserController::RBACUserController() :
|
||||
|
||||
RBACUserController::~RBACUserController() {
|
||||
}
|
||||
|
||||
// returnring true means handled, false means continue
|
||||
bool RBACUserSessionSetupMiddleware::on_before_handle_request_main(Request *request) {
|
||||
if (request->session) {
|
||||
int user_id = request->session->get_int("user_id");
|
||||
|
||||
if (user_id != 0) {
|
||||
|
||||
Ref<RBACUser> u = UserController::get_singleton()->db_get_user(user_id);
|
||||
|
||||
if (u.is_valid()) {
|
||||
request->reference_data["user"] = u;
|
||||
} else {
|
||||
// log
|
||||
request->session->remove_int("user_id");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
RBACUserSessionSetupMiddleware::RBACUserSessionSetupMiddleware() {
|
||||
}
|
||||
RBACUserSessionSetupMiddleware::~RBACUserSessionSetupMiddleware() {
|
||||
}
|
||||
|
||||
// returnring true means handled, false means continue
|
||||
bool RBACDefaultUserSessionSetupMiddleware::on_before_handle_request_main(Request *request) {
|
||||
// note: add a new file handler middleware func, so basic file handling is easy to set up before this
|
||||
|
||||
Ref<RBACRank> rank;
|
||||
|
||||
if (request->session) {
|
||||
int user_id = request->session->get_int("user_id");
|
||||
|
||||
if (user_id != 0) {
|
||||
|
||||
Ref<RBACUser> u = UserController::get_singleton()->db_get_user(user_id);
|
||||
|
||||
if (u.is_valid()) {
|
||||
rank = u->rbac_rank;
|
||||
|
||||
request->reference_data["user"] = u;
|
||||
} else {
|
||||
// log
|
||||
request->session->remove_int("user_id");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!rank.is_valid()) {
|
||||
rank = RBACController::get_singleton()->get_default_rank();
|
||||
|
||||
if (!rank.is_valid()) {
|
||||
if (RBACController::get_singleton()->continue_on_missing_default_rank()) {
|
||||
RLOG_ERR("get_default_rank() has not been set up properly!!! Continuing!");
|
||||
return false;
|
||||
} else {
|
||||
RLOG_ERR("get_default_rank() has not been set up properly!!! Sending 404!");
|
||||
request->send_error(404);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!rank->has_permission(request, User::PERMISSION_READ)) {
|
||||
if (rank->has_rank_permission(RBAC_RANK_PERMISSION_USE_REDIRECT)) {
|
||||
// Note this can make the webapp prone to enumerations, if not done correctly
|
||||
// e.g. redirect from /admin, but sending 404 on a non existing uri, which does not have
|
||||
// a special rbac entry
|
||||
request->send_redirect(RBACController::get_singleton()->get_redirect_url());
|
||||
return true;
|
||||
}
|
||||
|
||||
request->send_error(404);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
RBACDefaultUserSessionSetupMiddleware::RBACDefaultUserSessionSetupMiddleware() {
|
||||
}
|
||||
RBACDefaultUserSessionSetupMiddleware::~RBACDefaultUserSessionSetupMiddleware() {
|
||||
}
|
||||
|
@ -3,17 +3,14 @@
|
||||
|
||||
#include "modules/users/user_controller.h"
|
||||
|
||||
#include "core/http/middleware.h"
|
||||
|
||||
class Request;
|
||||
|
||||
class RBACUserController : public UserController {
|
||||
RCPP_OBJECT(RBACUserController, UserController);
|
||||
|
||||
public:
|
||||
// just session setup
|
||||
static void rbac_user_session_setup_middleware(Object *instance, Request *request);
|
||||
// this one also handles missing read permission / redirect
|
||||
static void rbac_default_user_session_middleware(Object *instance, Request *request);
|
||||
|
||||
// db
|
||||
|
||||
Ref<User> db_get_user(const int id);
|
||||
@ -29,4 +26,29 @@ public:
|
||||
protected:
|
||||
};
|
||||
|
||||
// just session setup
|
||||
class RBACUserSessionSetupMiddleware : public Middleware {
|
||||
RCPP_OBJECT(RBACUserSessionSetupMiddleware, Middleware);
|
||||
|
||||
public:
|
||||
//returnring true means handled, false means continue
|
||||
bool on_before_handle_request_main(Request *request);
|
||||
|
||||
RBACUserSessionSetupMiddleware();
|
||||
~RBACUserSessionSetupMiddleware();
|
||||
};
|
||||
|
||||
// this one also handles missing read permission / redirect
|
||||
class RBACDefaultUserSessionSetupMiddleware : public Middleware {
|
||||
RCPP_OBJECT(RBACDefaultUserSessionSetupMiddleware, Middleware);
|
||||
|
||||
public:
|
||||
//returnring true means handled, false means continue
|
||||
bool on_before_handle_request_main(Request *request);
|
||||
|
||||
RBACDefaultUserSessionSetupMiddleware();
|
||||
~RBACDefaultUserSessionSetupMiddleware();
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -503,26 +503,6 @@ void UserController::create_validators() {
|
||||
}
|
||||
}
|
||||
|
||||
void UserController::user_session_setup_middleware(Object *instance, Request *request) {
|
||||
if (request->session) {
|
||||
int user_id = request->session->get_int("user_id");
|
||||
|
||||
if (user_id != 0) {
|
||||
|
||||
Ref<User> u = UserController::get_singleton()->db_get_user(user_id);
|
||||
|
||||
if (u.is_valid()) {
|
||||
request->reference_data["user"] = u;
|
||||
} else {
|
||||
// log
|
||||
request->session->remove_int("user_id");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
request->next_stage();
|
||||
}
|
||||
|
||||
Ref<User> UserController::db_get_user(const int id) {
|
||||
if (id == 0) {
|
||||
return Ref<User>();
|
||||
@ -810,3 +790,30 @@ FormValidator *UserController::_profile_validator = nullptr;
|
||||
|
||||
String UserController::_path = "./";
|
||||
String UserController::_table_name = "users";
|
||||
|
||||
|
||||
// returnring true means handled, false means continue
|
||||
bool UserSessionSetupMiddleware::on_before_handle_request_main(Request *request) {
|
||||
if (request->session) {
|
||||
int user_id = request->session->get_int("user_id");
|
||||
|
||||
if (user_id != 0) {
|
||||
|
||||
Ref<User> u = UserController::get_singleton()->db_get_user(user_id);
|
||||
|
||||
if (u.is_valid()) {
|
||||
request->reference_data["user"] = u;
|
||||
} else {
|
||||
// log
|
||||
request->session->remove_int("user_id");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
UserSessionSetupMiddleware::UserSessionSetupMiddleware() {
|
||||
}
|
||||
UserSessionSetupMiddleware::~UserSessionSetupMiddleware() {
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "core/http/web_node.h"
|
||||
|
||||
#include "user.h"
|
||||
#include "core/http/middleware.h"
|
||||
|
||||
class Request;
|
||||
class FormValidator;
|
||||
@ -62,8 +63,6 @@ public:
|
||||
|
||||
virtual void create_validators();
|
||||
|
||||
static void user_session_setup_middleware(Object *instance, Request *request);
|
||||
|
||||
// db
|
||||
|
||||
virtual Ref<User> db_get_user(const int id);
|
||||
@ -104,4 +103,17 @@ protected:
|
||||
static String _table_name;
|
||||
};
|
||||
|
||||
// just session setup
|
||||
class UserSessionSetupMiddleware : public Middleware {
|
||||
RCPP_OBJECT(UserSessionSetupMiddleware, Middleware);
|
||||
|
||||
public:
|
||||
//returnring true means handled, false means continue
|
||||
bool on_before_handle_request_main(Request *request);
|
||||
|
||||
UserSessionSetupMiddleware();
|
||||
~UserSessionSetupMiddleware();
|
||||
};
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user