硬汉嵌入式论坛

 找回密码
 立即注册
查看: 713|回复: 1
收起左侧

[LwIP] 分享一个lwip httpd模块的cookie管理实现

[复制链接]

2

主题

5

回帖

11

积分

新手上路

积分
11
发表于 2023-9-15 00:44:01 | 显示全部楼层 |阅读模式
参考:

https://savannah.nongnu.org/patch/?9576

之前在项目上用lwip搭建了一个web服务器,想加个简单的登陆验证模块,但是逛了一圈发现lwip自带的httpd没有授权验证的接口,在官网找到一个patch,但是那个方案也稍微有点繁琐,需要客户端js协作实现,所以自己在上述patch的基础上魔改了一下,实现了一个cookie验证模块。

验证流程,客户端 输入用户名和密码通过POST或GET发送登录请求--->服务器验证通过,生成一个cookie,并通过Set-Cookie头返回给浏览器。cookie通过一个链表来维护,如果cookie数量超出限制,则会自动销毁最早生成的cookie,另外f每个cookie也有生命周期,超时后也会自动销毁。

由于代码格式化重新过,代码风格和lwip原风格有差异。

主要提供的接口:
void httpd_login_set(void *connection); // 当服务器验证成功时调用,httpd response时会自动添加set-cookie


如果需要修改cookie验证的处理流程,可以自行修改cookies.c中的 httpd_authorized_for_uri函数(比如可以设置css js之类的不需要验证,或者修改验证失败时应该返回的uri(可能要修改函数原型)):
int httpd_authorized_for_uri(void *connection, const char *uri, u32_t uri_len) {
    if (httpd_login_auth(connection) == 1) {
        return HTTP_AUTH_SET_COOKIE;
    }
    if ((lwip_strnistr(uri, "html", uri_len) == NULL) || (httpd_cookie_auth(connection) == 1)) {
        return HTTP_AUTH_OK;
    }
    return HTTP_AUTH_DENIED;
}



宏定义:
#define LWIP_HTTPD_SUPPORT_AUTH_COOKIE      1
#define LWIP_HTTPD_AUTH_COOKIE_NAME         "Session"
#define LWIP_HTTPD_AUTH_COOKIE_LENGTH       16
#define LWIP_HTTPD_AUTH_COOKIE_MAX_AGE      (30 * 60)   // 30 min
#define LWIP_HTTPD_AUTH_DENIED_FILE         "/index.shtml"
#define LWIP_HTTPD_AUTH_SESSION_MAXNUM      5



核心代码是在之前提过的patch上修改的,主要有两部分,
一部分是解析request的cookie头(原patch可能会误识别cookie值的结束符,所以我修改了一下,先判断请求头的结束符"\r\n",再判断中间是否有分隔符";",以获取准确的cookie长度):
/* Search for Auth cookie */
u8_t new_auth = 0;
u32_t cookie_len;
char *cookie, *end_crlf, *end_semi;
cookie = lwip_strnstr(data, HTTP_REQUEST_HDR_COOKIE_PREFIX, data_len);
if (cookie != NULL) {
    cookie += HTTP_REQUEST_HDR_COOKIE_PREFIX_LENGTH;
    cookie_len = data_len - (cookie - data);
    /* Cookie value ends with ';' or CRLF */
    end_crlf = lwip_strnstr(cookie, CRLF, cookie_len);
    if (end_crlf != NULL) {
        cookie_len = end_crlf - cookie;
        end_semi = lwip_strnstr(cookie, ";", cookie_len);
        if (end_semi != NULL) {
            cookie_len = end_semi - cookie;
        }
        if (cookie_len == LWIP_HTTPD_AUTH_COOKIE_LENGTH && httpd_cookie_verify(cookie) == true) {
            new_auth = 1;
        }
    }
}
hs->auth = new_auth;



第二部分是验证uri请求(http_find_file), 如果是登录请求,则自动添加Set-Cookie头(增加了一个请求头,可能需要开启 LWIP_HTTPD_DYNAMIC_HEADERS),如果拒绝该请求,则uri重定向到预定义的一个uri(可根据自己需求修改)。
hs->hdrs[HDR_STRINGS_IDX_SET_COOKIES] = NULL;

LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Check authorization for %s\n", uri));
int ret = httpd_authorized_for_uri(hs, uri, uri_len);
if (ret == HTTP_AUTH_DENIED) {
    uri = LWIP_HTTPD_AUTH_DENIED_FILE;
    params = NULL;        // Ignore any parameters in the query string
    LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE,
                ("Authorization failed, landing to %s\n", LWIP_HTTPD_AUTH_DENIED_FILE));
} else if (ret == HTTP_AUTH_SET_COOKIE) {
    const char *cookie_string = httpd_cookie_generate();
    LWIP_ASSERT("Cookie string is NULL", cookie_string != NULL);
    snprintf(hs->hdr_set_cookie,
             HTTP_HDR_SET_COOKIE_BUFFER_LENGTH,
             "%s%s;%s%u\r\n",
             HTTP_HDR_SET_COOKIE_PREFIX,
             cookie_string,
             HTTP_HDR_SET_COOKIE_MAXAGE,
             LWIP_HTTPD_AUTH_COOKIE_MAX_AGE);
    hs->hdrs[HDR_STRINGS_IDX_SET_COOKIES] = hs->hdr_set_cookie;
    LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Authorization success, set cookies: %s\n", cookie_string));
}



cookie 部分的主要代码都在cookies.c中,需要一个定时器来实现cookie的生命周期管理,另外还需要一个随机数生成器来生成cookie。



lwip_httpd_cookie_auth.zip

46.15 KB, 下载次数: 11

评分

参与人数 1金币 +100 收起 理由
eric2013 + 100 很给力!

查看全部评分

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106731
QQ
发表于 2023-9-15 09:10:52 | 显示全部楼层
谢谢楼主分享。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-3 00:09 , Processed in 0.163725 second(s), 30 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表