中间件和过滤器
在调用接口时 需要先判断是否登录 可以在触发handler前 先调用filter 过滤器的作用
中间件是洋葱圈模型
框架做完路由匹配后 会依次调用路径上的中间件 功能是 放行和拦截 前置处理 后置处理
例如拦截一个请求后 不会触发handler 但是可以触发中间件的后置处理
过滤器实际上就是省略后置操作的中间件
自定义中间件
class MyMiddleware : public HttpMiddleware<MyMiddleware>{
public:
MyMiddleware(){};
void invoke(const HttpRequestPtr &req,
MiddlewareNextCallback &&nextCb,
MiddlewareCallback &&mcb
) override
{
const std::string &origin = req->getHeader("origin");
if (origin.find("127.0.0.1") != std::string::npos)
{
mcb(HttpResponse::newNotFoundResponse(req));
return;
}
nextCb([mcb = std::move(mcb)](const HttpResponsePtr &resp) {
resp->addHeader("Access-Control-Allow-Origin", origin);
resp->addHeader("Access-Control-Allow-Credentials","true");
mcb(resp);
});
}
};
自定义过滤器
class LoginFilter:public drogon::HttpFilter<LoginFilter>{
public:
void doFilter(const HttpRequestPtr &req,
FilterCallback &&fcb,
FilterChainCallback &&fccb
) override ;
};
注册
METHOD_ADD(User::getInfo,"/{1}/info?token={2}",Get,"LoginFilter","MyMiddleware");
会话 session
直接复制的官网示例 实际使用时 在确认是否有问题
#include "TimeFilter.h"
#include <trantor/utils/Date.h>
#include <trantor/utils/Logger.h>
#define VDate "visitDate"
void TimeFilter::doFilter(const HttpRequestPtr &req,
FilterCallback &&cb,
FilterChainCallback &&ccb)
{
trantor::Date now=trantor::Date::date();
LOG_TRACE<<"";
if(req->session()->find(VDate))
{
auto lastDate=req->session()->get<trantor::Date>(VDate);
LOG_TRACE<<"last:"<<lastDate.toFormattedString(false);
req->session()->modify<trantor::Date>(VDate,
[now](trantor::Date &vdate) {
vdate = now;
});
LOG_TRACE<<"update visitDate";
if(now>lastDate.after(10))
{
ccb();
return;
}
else
{
Json::Value json;
json["result"]="error";
json["message"]="Access interval should be at least 10 seconds";
auto res=HttpResponse::newHttpJsonResponse(json);
cb(res);
return;
}
}
LOG_TRACE<<"first access,insert visitDate";
req->session()->insert(VDate,now);
ccb();
}
drogon::HttpAppFramework::instance().enableSession(1200);
jwt-cpp
概念
jwt 是 Json web token 作用 验证信息
其他的里面 介绍的很清楚
安装等直接看文档即可
官方提供字段
header 信息
介绍 | 使用 | key | value |
---|
类型接扫 | .set_type(“JWS”) | typ | JWS |
使用算法 | .set_algorithm(“hs256”) | alg | hs256 |
内容类型 | .set_content_type(“contentType”) | cty | contentType |
kei_id | .set_key_id(“key_id”) | kid | key_id |
payload 信息
介绍 | 使用 | key | value |
---|
接收者 | .set_audience(“audienceVal”) | aud | audienceVal |
签发者 | .set_issuer(“issuerVal”) | iss | issuerVal |
编号 | .set_id(“idVal”) | jti | idVal |
主题 | .set_subject(“subjectVal”) | sub | subjectVal |
其他的对比
.set_expires_at();
具体日期过期
.set_expires_in(); exp -- 时间戳 推荐用此
多久以后过期
.set_issued_at();
指定签发时间
.set_issued_now(); iat -- 时间戳 推荐用此
自动设置当前时间
.set_not_before()
设置生效时间
.set_header_claim() 设置header 信息
.set_payload_claim() 设置payload 信息
创建jwt
std::string createToken(const std::string& userId) {
std::chrono::duration<int> durationTime(14400);
auto token = jwt::create()
.set_type("JWS")
.set_algorithm("HS256")
.set_issued_now()
.set_expires_in(durationTime)
.set_payload_claim("userId",jwt::claim(userId))
.sign(jwt::algorithm::hs256{"密钥"});
return token;
}
解析
std::map<std::string,std::string> verifyToken(const std::string& token){
std::map<std::string,std::string> resMap;
const std::string authNo = "401";
const std::string authYes = "200";
if(token.empty()){
resMap["status"] = authNo;
return resMap;
};
try{
auto tokenDecode = jwt::decode(token);
jwt::verify()
.allow_algorithm(jwt::algorithm::hs256("密钥"))
.verify(tokenDecode);
auto tokenData = tokenDecode.get_payload_json();
std::string userId = tokenData["userId"].to_str();
int expTime = std::stoi(tokenData["exp"].to_str());
auto now = std::chrono::system_clock::now();
auto nowTimestamp = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count();
if(expTime - nowTimestamp <= 0){
resMap["status"] = authNo;
return resMap;
} else if(expTime - nowTimestamp <= 600){
}
resMap["status"] = authYes;
resMap["userId"] = userId;
return resMap;
}catch(const jwt::error::token_verification_exception& err){
resMap["status"] = authNo;
return resMap;
}
}
jwt 使用简单 但是不能传敏感信息,比如密码等,因为会被在线解析出来
所以服务端使用时除了解析之外必须增加验证环节
关于token自动续期 实现的方式很多 前端无感刷新的方法没想到。
有一种办法是 建立key-jwt的机制 将jwt 存到数据库中 然后id不变的情况下 更新jwt的过期时间
但是 都操作数据库了 那还用什么jwt 方法更多了。所以前端无感刷新还没想到其他方法