这是我参与8月更文挑战的第15天,活动详情查看:8月更文挑战
过滤器
通常来说,一个聊天室在用户注册和登陆之后,访问其他接口时需要对其进行身份验证,在用户登陆后,登陆接口会为用户返回一个JWT token,用户需要在访问其他资源、接口时带上这个token,其中一种方式是称为Bearer的认证方式
Bearer
Bearer认证方式具体的资料可以在这里找到 Bearer,简单来说,在用户获得Token之后,需要在http header中带上。
Authorization: Bearer <token>
服务端解析得到token之后对其身份进行校验。
为了实现身份校验的拦截功能,通常在HTTP服务中通过过滤器或拦截器实现。
Flare Http Filter
flare中提供了一个HttpFilter的基类,如下:
class HttpFilter {
public:
virtual ~HttpFilter() = default;
// Action to be taken by the framework.
enum class Action {
// Call next filter, or there is none, the actual HTTP handler.
KeepProcessing,
// Drop this request, nothing will be returned in this case. No futher
// action (e.g. calling remaining filters, calling the actual HTTP handler)
// is required.
Drop,
// Return immediately with what's filled in `response`, any pending filter
// will not be called, neither will be the actual HTTP handler.
EarlyReturn
};
// The framework calls this method before handing request to corresponding
// handler.
//
// The implementation may mutate any of arguments if it deems fit. But be
// caution not to confuse other filters / handler.
virtual Action OnFilter(HttpRequest* request, HttpResponse* response,
HttpServerContext* context) = 0;
};
HttpFilter会在HttpHandler调用之前,以链式调用的方式调用每个filter,filter中可以对用户的request进行解析和判定,可以对response进行填充,返回值有三种,可以继续执行、直接丢弃和提前返回,我们通过实现一个HttpFilter的子类去实现接口的拦截,具体的身份验证Filter如下:
class LoginFilter : public flare::HttpFilter {
private:
flare::detail::UriMatcher _uri_matcher;
public:
explicit LoginFilter(flare::detail::UriMatcher uri_matcher = {});
virtual ~LoginFilter() = default;
Action OnFilter(flare::HttpRequest* request, flare::HttpResponse* response,
flare::HttpServerContext* context) override;
};
std::optional<std::string_view> ParseCredential(std::string_view cred) {
// Authorization:
static constexpr auto kPrefix = "Bearer "sv;
if (!flare::StartsWith(cred, kPrefix)) {
return std::nullopt;
}
return cred.substr(kPrefix.size());
}
LoginFilter::LoginFilter(flare::detail::UriMatcher uri_matcher)
: _uri_matcher(std::move(uri_matcher)) {}
flare::HttpFilter::Action LoginFilter::OnFilter(
flare::HttpRequest* request, flare::HttpResponse* response,
flare::HttpServerContext* context) {
if (_uri_matcher(request->uri())) {
return Action::KeepProcessing;
}
auto token =
ParseCredential(request->headers()->TryGet("Authorization").value_or(""));
if (!token) {
response->set_status(flare::HttpStatus::BadRequest);
return Action::EarlyReturn;
}
auto username = TokenUtil::Instance()->VerifyToken(*token);
if (!username) {
response->set_status(flare::HttpStatus::BadRequest);
return Action::EarlyReturn;
}
request->headers()->Append("username", *username);
return LoginFilter::Action::KeepProcessing;
}
在上述程序中,我们在OnFilter中实现了Bearer认证方式的解析,解析出token、然后调用jwt-cpp的接口对其进行正确性验证,当验证不通过时,设置相应状态为BadRequest,直接提前返回,若验证通过,则继续后面的处理过程。 在filter中,有一个UriMatcher类型的成员变量,用于对uri进行过滤,当匹配到uri时,不进行身份验证。
增加Filter
在http server上,我们也需要将我们实现的filter配置上去。
server.AddHttpFilter(std::make_unique<LoginFilter>(flare::detail::UriMatcher(std::regex("^/user(Login([/\?#](.*?))?)?$"))));
通过AddHttpFilter接口增加了LogFilter,并配置了用户注册和用户登陆等接口不用进行身份验证。
小结
本文为大家介绍了Flare中Http filter的实现方式,由于Http restful接口通常通过Json格式传输数据,所以接下来介绍一下c++中,如何方便的处理Json数据到Struct的相互转换。