首页 > 数据库 >PostgreSQL学习之基于时间的认证

PostgreSQL学习之基于时间的认证

时间:2024-07-03 16:01:23浏览次数:15  
标签:基于 PostgreSQL timerange 00 认证 char time return NULL

       设计

        如果要限制用户在某一天的某时间段可以登录,某时间段不可以登录,在此做了一种简单的实现,通过pg_hba.conf文件配置时间段,示例如下:

# TYPE  DATABASE        USER            ADDRESS         TIME        METHOD

# "local" is for Unix domain socket connections only
local   all             all                                     trust
# IPv4 local connections:
host    all             postgres,user1             127.0.0.1/32    "MonTueWedThuFri|08:00:00-10:00:00,SatSun|10:00:00-16:00:00"     md5
# IPv6 local connections:
host    all             all             ::1/128       "MonTueWedThuFri|08:00:00-20:00:00,SatSun|10:00:00-16:00:00"          trust
# Allow replication connections from localhost, by a user with the
# replication privilege.
local   replication     all                                     trust
host    replication     all             127.0.0.1/32     "MonTueWedThuFri|08:00:00-20:00:00,SatSun|10:00:00-16:00:00"       trust
host    replication     all             ::1/128           "MonTueWedThuFri|08:00:00-20:00:00,SatSun|10:00:00-16:00:00"      trust

        如上:

        1、增加TIME字段设置时间段配置;

        2、针对本地登录(local)不做设置;

        3、时间段规则解析:

                1)每一条配置可以设置多组时间段,以","分割;

                2)每一组时间段可以对应多天,以"|"分割,比如上例中的“MonTueWedThuFri|08:00:00-10:00:00”代表周一到周五五天每天的8:00到10点都可以登录;

                3)每一组内只能有一个时间段,不能出现多个时间段,如果要配置某一天多个时间段可以登录,可以配置多组,每一组代表一个时间段。假如周一周二两天允许上午和下午两个时间段登录,可以这么配置:

"MonTue|09:00:00-11:00:00,MonTue|13:00:00-15:00:00"

                4)时间段设置以周为单位,时间要具体到秒,以英文缩写(前三个字母,第一个大写,第二个第三个小写)代表每周的某一天。

        实现

        基于postgresql14.7的源代码实现如下:

        1、解析:parse_hba_line函数逐条解析pg_hba.conf中的配置,在此新增对TIME字段的解析并保存,解析的同时需要检查设置是否符合规则或错误,检查代码如下:

static int timerange_check_day(char *days) {
    char day[4];
    day[3] = '\0';
    for(int i = 0;i < strlen(days); i += 3){
        memcpy(day, days + i, 3);
        if (strcmp(day, "Mon") != 0 && strcmp(day, "Tue") != 0 && strcmp(day, "Wed") != 0 &&
            strcmp(day, "Thu") != 0 && strcmp(day, "Fri") != 0 && strcmp(day, "Sat") != 0 &&
            strcmp(day, "Sun") != 0) {
            return 0;
        }
    }
    return 1;
}

static int timerange_check_time(char *time) {
    int h1, m1, s1, h2, m2, s2;
    if (sscanf(time, "%02d:%02d:%02d-%02d:%02d:%02d", &h1, &m1, &s1, &h2, &m2, &s2) != 6) {
        return 0;
    }
    if (h1 < 0 || h1 > 23 || m1 < 0 || m1 > 59 || s1 < 0 || s1 > 59 ||
        h2 < 0 || h2 > 23 || m2 < 0 || m2 > 59 || s2 < 0 || s2 > 59) {
        return 0;
    }
    return 1;
}

static int timerange_check_group(char *group) {
    char *saveptr1 = NULL;
    char *saveptr2 = NULL;
    char *token = NULL;
    char *days = NULL;
    char *time = NULL;
    char *day = NULL;
    int day_count = 0;

    token = strtok_r(group, "|", &saveptr1);
    if (token == NULL) {
        return 0;
    }
    days = token;
    token = strtok_r(NULL, "|", &saveptr1);
    if (token == NULL) {
        return 0;
    }
    time = token;

    // 检查 days 部分
    day = strtok_r(days, "", &saveptr2);
    while (day != NULL) {
        if (!timerange_check_day(day)) {
            return 0;
        }
        day_count++;
        day = strtok_r(NULL, "", &saveptr2);
    }
    if (day_count < 1 || day_count > 7) {
        return 0;
    }

    // 检查 time 部分
    if (!timerange_check_time(time)) {
        return 0;
    }

    return 1;
}

static int timerange_check_rule(char *rule) {
    char *saveptr = NULL;
    char *token = strtok_r(rule, ",", &saveptr);
    while (token != NULL) {
        if (!timerange_check_group(token)) {
            return 0;
        }
        token = strtok_r(NULL, ",", &saveptr);
    }
    return 1;
}

static bool timerange_time_check(char *timestr) {
    char *rule = pstrdup(timestr);

    if (timerange_check_rule(rule))
        return true;

    return false;
}

        2、登录检查:客户端登录时,在函数check_hba中新增时间检查,检查当前日期和时间点是否在配置的时间段范围内,时间点检查函数如下:

typedef struct {
  char days[100];
  char start_time[10];
  char end_time[10];
} TimePeriod;

static void timerange_getCurrentTime(char *current_time) {
  time_t now = time(NULL);
  struct tm *t = localtime(&now);
  sprintf(current_time, "%02d:%02d:%02d", t->tm_hour, t->tm_min, t->tm_sec);
}

static void timerange_getCurrentDate(char *current_date) {
  time_t now = time(NULL);
  struct tm *t = localtime(&now);
  sprintf(current_date, "%d-%02d-%02d", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday);
}

static int timerange_getCurrentWeekday() {
  time_t now = time(NULL);
  struct tm *t = localtime(&now);
  return t->tm_wday;
}

static int timerange_compareTime(const char *time1, const char *time2) {
  int h1, m1, s1, h2, m2, s2;
  sscanf(time1, "%d:%d:%d", &h1, &m1, &s1);
  sscanf(time2, "%d:%d:%d", &h2, &m2, &s2);
  if (h1 < h2) {
    return -1;
  } else if (h1 > h2) {
    return 1;
  } else {
    if (m1 < m2) {
      return -1;
    } else if (m1 > m2) {
      return 1;
    } else {
      if (s1 < s2) {
        return -1;
      } else if (s1 > s2) {
        return 1;
      } else {
        return 0;
      }
    }
  }
}

static int timerange_checkTimePeriod(TimePeriod *period, char *current_time) {
  int start_comp = timerange_compareTime(period->start_time, current_time);
  int end_comp = timerange_compareTime(period->end_time, current_time);
  return start_comp <= 0 && end_comp >= 0;
}

static int timerange_checkDay(char *days, int current_weekday) {
  char weekdays[][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};

  if (current_weekday >= 0 && current_weekday < 7 && (strstr(days, weekdays[current_weekday]) != NULL)) {
      return 1;
  }
  return 0;
}

static bool check_timerange(char *timestr) {

    char *token = NULL;
    char *rules = pstrdup(timestr);

    char current_time[10];
    char current_date[20];

    int current_weekday = timerange_getCurrentWeekday();

    char *saveptr1, *saveptr2, *saveptr3;
    timerange_getCurrentTime(current_time);
    timerange_getCurrentDate(current_date);

    token = strtok_r(rules, ",", &saveptr1);
    while (token != NULL) {
        char *days_time = NULL;
        char *time_range = NULL;
        char *start_time = NULL;
        char *end_time = NULL;
        TimePeriod period;
        days_time = strtok_r(token, "|", &saveptr2);
        strcpy(period.days, days_time);
        time_range = strtok_r(NULL, "|", &saveptr2);
        start_time = strtok_r(time_range, "-", &saveptr3);
        strcpy(period.start_time, start_time);
        end_time = strtok_r(NULL, "-", &saveptr3);
        strcpy(period.end_time, end_time);

        if (timerange_checkDay(period.days, current_weekday) && timerange_checkTimePeriod(&period, current_time))
            return true;

        token = strtok_r(NULL, ",", &saveptr1);
  }

  return false;
}

        至此,基于时间的登录设置功能已实现,如果考虑到视图pg_hba_file_rules的正确展现hba文件的设置,还需要做如下修改:

         3、修改视图pg_hba_file_rules,新增时间范围字段:

{ oid => '3401', descr => 'show pg_hba.conf rules',
  proname => 'pg_hba_file_rules', prorows => '1000', proretset => 't',
  provolatile => 'v', prorettype => 'record', proargtypes => '',
  proallargtypes => '{int4,text,_text,_text,text,text,text,text,_text,text}',
  proargmodes => '{o,o,o,o,o,o,o,o,o,o}',
  proargnames => '{line_number,type,database,user_name,address,netmask,timerange,auth_method,options,error}',
  prosrc => 'pg_hba_file_rules' },

        4、修改一个宏原为9改为10,因为上面的视图原来是9个字段,现在新增一个字段变为10个:

#define NUM_PG_HBA_FILE_RULES_ATTS	 10

        5、在函数fill_hba_line函数中新增对新增字段timerange的填充。

        6、最后最好修改src/backend/libpq/pg_hba.conf.sample,在模板文件中配置上默认的时间段。

        完整的时间规则检查和时间点检查测试验证用例详见:

【免费】基于规则“SunThu-00:02:00-00:03:00,Mon-16:59:00-20:00:00”时间范围检查(C语言)资源-CSDN文库

        思考

        如何才能更灵活、更清晰明了的配置时间范围?

        可不可以通过插件方式实现?

        ......

标签:基于,PostgreSQL,timerange,00,认证,char,time,return,NULL
From: https://blog.csdn.net/weixin_38700215/article/details/140151625

相关文章

  • PostgreSQL学习之使用LDAP认证
        PostgreSQL使用LDAP认证,简单说就是将用户名和密码存储在LDAP服务器上,postgresql数据库必须有相同的用户(用户名称相同,密码可以不同),当数据库客户端登录数据库时,数据库服务器不使用本地的密码校验机制而是去请求LDAP服务器验证用户名密码是否正确,正确则登录成功,失败......
  • 基于Java+Vue的智慧园区管理系统:创新园区运营模式,构建全方位企业服务体系(代码分享)
     前言:智慧园区管理系统是一个集成了多种功能的综合性系统,旨在通过信息化、智能化手段提升园区的管理效率和服务质量。以下是针对系统的各个功能模块的简要描述:一、楼栋管理会务管理:管理园区内的会议预约、会议室使用等。园区信息:展示园区的基本信息,如位置、面积、规划等。......
  • 基于Java+Vue的企事业移动培训考试系统:体系化培训管理,保障培训效果(代码分享)
     前言:企事业移动培训考试系统是一个集成多种功能的综合性平台,旨在为企业提供便捷、高效、灵活的在线培训和考试解决方案。以下是针对平台所列出的八个主要功能的详细解释:一、文档管理及在线预览允许企业上传、存储、管理和分享各种培训文档,如PPT、PDF、Word等。提供在线预......
  • 保持校园网自动登录的代码备忘: 基于webdriver和chrome
    在跑一个处理很多数据的代码,需要不间断地运行。而且最近打算回家一周,需要远程控制电脑。但是学校的校园网每到晚上就会自己断开,干脆写份脚本来保持校园网的连接这份简单的代码只包括三个部分,检测网络状态的部分,自动登录校园网的部分,循环执行的部分、importosimporttimeimpo......
  • 动手学Avalonia:基于SemanticKernel与硅基流动构建AI聊天与翻译工具
    Avalonia是什么?Avalonia是一个跨平台的UI框架,专为.NET开发打造,提供灵活的样式系统,支持Windows、macOS、Linux、iOS、Android及WebAssembly等多种平台。它已成熟并适合生产环境,被SchneiderElectric、Unity、JetBrains和GitHub等公司采用。许多人认为Avalonia是WPF的继任者,它为XA......
  • 基于YOLOv5的人脸关键点检测(附代码)
    人脸关键点检测项目说明本项目的实现主要依靠两个算法:yolov5目标检测和resnet人脸关键点算法。其中目标检测算法为人脸关键点检测算法的前置算法,使用目标检测算法将人脸信息进行提取(起到前景与背景的分离),然后再对box内的人脸信息进行关键点检测。本项目支持功能:人脸关键......
  • 基于R语言BIOMOD2 及机器学习方法的物种分布模拟与案例分析------生物多样性保护、气
     BIOMOD2是一个用于物种分布模拟的模型,它在生态学和生物多样性保护领域有着广泛的应用。该模型能够模拟特定物种与其环境之间的关系,利用环境变量来模拟特定物种的生态位。BIOMOD2提供了运行多达10余种物种分布模拟模型的能力BIOMOD2模型的运行涉及多个步骤,包括物种分布文件的......
  • 简单课设:基于TCP协议的客户/服务器聊天室
            随着计算机的普及,网络编程也显得愈发重要,同时掌握实现客户/服务器程序的编写方法也不可忽视。通过学习,我们将了解TCP协议在网络通信中的重要性,掌握如何使用在Linux或Windows平台上编写简单的TCP客户/服务器程序。课程设计分为两个部分:服务器端和客户端。在服务......
  • 基于Java的宠物领养管理系统
    目录        一、系统简介1.需求分析2 .编程环境与工具二、系统总体设计1.系统的功能模块图2.系统架构3.系统部署和测试步骤4.各功能模块简介(1)主页:(2)宠物知识:(3)领养中心:(4)团队博客:(5)团队展示:(6)注册/登录:三、主要业......
  • 小白新手基于云数据库 Redis 搭建 游戏排行榜
    小白新手基于云数据库Redis搭建游戏排行榜免费试用搭建游戏排行榜搭建基础环境JDK、Maven部署游戏排行榜写在最后操作感受其他应用免费试用在开始搭建游戏排行榜之前,我们首先需要领取阿里云社区为我们准备的免费资源,比如云数据库Redis版免费试用点击【立即......