读 drogonwiki 笔记总结记录2

中间件和过滤器

在调用接口时 需要先判断是否登录 可以在触发handler前 先调用filter  过滤器的作用
中间件是洋葱圈模型 
    框架做完路由匹配后 会依次调用路径上的中间件 功能是 放行和拦截 前置处理 后置处理
        例如拦截一个请求后 不会触发handler 但是可以触发中间件的后置处理
    过滤器实际上就是省略后置操作的中间件

自定义中间件

// 为某路由开启跨域支持 中间件
class MyMiddleware : public HttpMiddleware<MyMiddleware>{
public:
    MyMiddleware(){};  // do not omit constructor

    // 重载此函数
    void invoke(const HttpRequestPtr &req,   // http请求
                MiddlewareNextCallback &&nextCb,  // 进入内层 执行下一个中间件或最终handler 从内层返回时 调用传递的函数参数
                MiddlewareCallback &&mcb //返回上层 若跳过nextCb只调用此 则意味着拦截请求 直接回上层 
            ) override
    {
        const std::string &origin = req->getHeader("origin");
        if (origin.find("127.0.0.1") != std::string::npos)
        {
            // intercept directly 如果是某origin 则直接拦截
            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 // 请求需要判断通过 调用此 调用下一个过滤器或最终handler
        ) override ;
};

注册

// 不需要引入 头文件
// 更多此处 需要查看记录1 
METHOD_ADD(User::getInfo,"/{1}/info?token={2}",Get,"LoginFilter","MyMiddleware");             

会话 session

直接复制的官网示例 实际使用时 在确认是否有问题

// 下面代码 复制于api文档 
#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))
        {
            //10 sec later can visit again;
            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 信息
介绍使用keyvalue
类型接扫.set_type(“JWS”)typJWS
使用算法.set_algorithm(“hs256”)alghs256
内容类型.set_content_type(“contentType”)ctycontentType
kei_id.set_key_id(“key_id”)kidkey_id
payload 信息
介绍使用keyvalue
接收者.set_audience(“audienceVal”)audaudienceVal
签发者.set_issuer(“issuerVal”)ississuerVal
编号.set_id(“idVal”)jtiidVal
主题.set_subject(“subjectVal”)subsubjectVal
其他的对比
.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){
	// 空401 错误 过期 200 成功
	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){
		    // 还有10分钟过期 自动续期
		    //  token自动续期  
		}
       // 否则没过期
       resMap["status"] = authYes;
       resMap["userId"] = userId;
       return resMap;
   }catch(const jwt::error::token_verification_exception& err){
       /*
        * 失败的 就直接401
        * 过期的 没传的 错误的 都要重新登陆
        * */
       resMap["status"] = authNo;
       return resMap;
   }
}
jwt 使用简单 但是不能传敏感信息,比如密码等,因为会被在线解析出来
所以服务端使用时除了解析之外必须增加验证环节
关于token自动续期 实现的方式很多 前端无感刷新的方法没想到。
有一种办法是 建立key-jwt的机制 将jwt 存到数据库中 然后id不变的情况下 更新jwt的过期时间
但是 都操作数据库了 那还用什么jwt 方法更多了。所以前端无感刷新还没想到其他方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hamburgerV

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值