代码

/* 作业增强版注册登录系统 - 带日志和安全性增强功能 */
#include <stdio.h>      // 标准输入输出函数(printf, scanf等)
#include <stdlib.h>     // 标准库函数(exit, malloc等)
#include <string.h>     // 字符串处理函数(strcmp, strcspn等)
#include <fcntl.h>      // 文件控制选项(open, O_RDWR等)
#include <unistd.h>     // POSIX系统调用(read, write等)
#include <time.h>       // 时间函数(time, localtime等)
#include <stdarg.h>     // 可变参数支持(va_list, va_start等)/* 系统常量定义 */
#define MAX_ATTEMPTS 3   // 允许的最大登录尝试次数
#define LOCK_TIME 8      // 账号锁定时间(秒) 
#define LOCK_FILE "login.lock"  // 存储锁定状态的文件名
#define USER_FILE "user.txt"    // 存储用户数据的文件名
#define LOG_FILE "system.log"   // 日志文件名/* 日志记录函数* 参数:format - 格式化字符串,... - 可变参数* 功能:将带时间戳的日志信息写入日志文件*/
void log_message(const char *format, ...) {FILE *log_file = fopen(LOG_FILE, "a");  // 以追加模式打开日志文件if (log_file) {  // 检查文件是否成功打开time_t now;  // 存储当前时间time(&now);  // 获取当前时间戳char time_str[20];  // 存储格式化后的时间字符串// 将时间转换为本地时间并格式化为字符串strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", localtime(&now));// 写入时间戳到日志文件fprintf(log_file, "[%s] ", time_str);// 处理可变参数va_list args;  // 定义可变参数列表va_start(args, format);  // 初始化可变参数vfprintf(log_file, format, args);  // 写入格式化内容到日志va_end(args);  // 结束可变参数处理fprintf(log_file, "\n");  // 写入换行符fclose(log_file);  // 关闭日志文件}
}/* 检查用户名是否已存在* 参数:username - 要检查的用户名* 返回值:1-存在,0-不存在*/
int is_username_exist(const char *username) {FILE *fp = fopen(USER_FILE, "r");  // 以只读方式打开用户文件if (fp) {  // 文件打开成功char file_user[20];  // 存储从文件读取的用户名// 逐行读取用户文件while (fgets(file_user, sizeof(file_user), fp)) {file_user[strcspn(file_user, "\n")] = '\0';  // 去除换行符// 比较用户名是否匹配if (strcmp(username, file_user) == 0) {fclose(fp);  // 关闭文件return 1;  // 返回1表示用户名已存在}// 跳过密码行(用户名和密码交替存储)if (!fgets(file_user, sizeof(file_user), fp)) break;}fclose(fp);  // 关闭文件}return 0;  // 返回0表示用户名不存在
}/* 检查账号是否处于锁定状态* 返回值:1-锁定中,0-未锁定*/
int is_locked() {FILE *fp = fopen(LOCK_FILE, "r");  // 打开锁定状态文件if (fp) {  // 文件存在time_t lock_time;  // 存储锁定时间fscanf(fp, "%ld", &lock_time);  // 读取锁定时间fclose(fp);  // 关闭文件time_t current = time(NULL);  // 获取当前时间// 检查是否仍在锁定期内if (current - lock_time < LOCK_TIME) {// 显示剩余锁定时间printf("账号锁定中,请等待%ld秒后重试\n", LOCK_TIME - (current - lock_time));// 记录锁定状态到日志log_message("账号锁定中,剩余时间: %ld秒", LOCK_TIME - (current - lock_time));return 1;  // 返回1表示仍处于锁定状态} else {remove(LOCK_FILE);  // 锁定已过期,删除锁定文件log_message("账号锁定已自动解除");  // 记录解锁日志}}return 0;  // 返回0表示未锁定
}/* 设置账号锁定状态* 功能:创建锁定文件并记录当前时间*/
void set_lock() {FILE *fp = fopen(LOCK_FILE, "w");  // 创建/覆盖锁定文件if (fp) {  // 文件创建成功fprintf(fp, "%ld", time(NULL));  // 写入当前时间戳fclose(fp);  // 关闭文件log_message("账号因连续登录失败被锁定");  // 记录锁定日志}
}/* 主函数 */
int main() {log_message("程序启动");  // 记录程序启动日志int flag = 0;  // 用户选择的功能标志(1=注册,2=登录)char username[20], password[20], confirm_pass[20];  // 注册用变量char user[20], pass[20];  // 登录用变量// 检查账号锁定状态if (is_locked()) {log_message("尝试访问被锁定的账号");return 1;  // 账号锁定中,直接退出程序}// 显示功能菜单printf("请选择功能:\n1.注册\n2.登录\n");scanf("%d", &flag);  // 读取用户选择getchar();  // 清除输入缓冲区中的换行符log_message("用户选择功能: %d", flag);  // 记录用户选择/* 注册功能处理 */if (flag == 1) {// 用户名输入循环while (1) {printf("请输入用户名:\n");fgets(username, 20, stdin);  // 安全读取用户名(防止缓冲区溢出)username[strcspn(username, "\n")] = '\0';  // 去除换行符// 检查用户名是否已存在if (is_username_exist(username)) {printf("用户名已存在,请重新输入\n");log_message("注册失败: 用户名 %s 已存在", username);continue;  // 用户名存在,重新输入}break;  // 用户名可用,退出循环}// 密码输入循环while (1) {printf("请输入密码:\n");fgets(password, 20, stdin);password[strcspn(password, "\n")] = '\0';printf("请再次输入密码确认:\n");fgets(confirm_pass, 20, stdin);confirm_pass[strcspn(confirm_pass, "\n")] = '\0';// 检查两次密码是否一致if (strcmp(password, confirm_pass) != 0) {printf("两次输入的密码不一致,请重新输入\n");log_message("注册失败: 密码不一致");continue;  // 密码不一致,重新输入}break;  // 密码一致,退出循环}// 保存用户信息FILE *fp = fopen(USER_FILE, "a");  // 以追加模式打开用户文件if (fp) {  // 文件打开成功fprintf(fp, "%s\n%s\n", username, password);  // 写入用户名和密码fclose(fp);  // 关闭文件printf("注册成功!\n");log_message("用户 %s 注册成功", username);  // 记录注册成功} else {perror("注册失败");  // 显示系统错误信息log_message("注册失败: 无法打开用户文件");  // 记录错误日志}}/* 登录功能处理 */else if (flag == 2) {int attempts = 0;  // 登录尝试次数计数器// 登录尝试循环(最多MAX_ATTEMPTS次)while(attempts < MAX_ATTEMPTS) {// 获取用户名printf("请输入用户名:\n");fgets(user, 20, stdin);user[strcspn(user, "\n")] = '\0';// 获取密码printf("请输入密码:\n");fgets(pass, 20, stdin);pass[strcspn(pass, "\n")] = '\0';// 验证用户凭据FILE *fp = fopen(USER_FILE, "r");  // 打开用户文件int found = 0;  // 标记是否找到匹配用户if (fp) {  // 文件打开成功char file_user[20], file_pass[20];  // 存储文件中的用户名和密码// 逐行读取用户文件while (fgets(file_user, sizeof(file_user), fp)) {file_user[strcspn(file_user, "\n")] = '\0';  // 去除换行符// 读取对应的密码行if (fgets(file_pass, sizeof(file_pass), fp)) {file_pass[strcspn(file_pass, "\n")] = '\0';  // 去除换行符// 比较用户名和密码if (strcmp(user, file_user) == 0 && strcmp(pass, file_pass) == 0) {found = 1;  // 标记为找到匹配用户break;}}}fclose(fp);  // 关闭文件}// 检查验证结果if (found) {  // 验证成功printf("登录成功!\n");log_message("用户 %s 登录成功", user);  // 记录登录成功break;  // 退出登录循环} else {  // 验证失败attempts++;  // 增加尝试次数log_message("登录失败: 用户名 %s 尝试失败 %d/%d", user, attempts, MAX_ATTEMPTS);if (attempts < MAX_ATTEMPTS) {  // 还有尝试机会printf("用户名或密码错误,请重新输入(剩余尝试次数: %d)\n",MAX_ATTEMPTS - attempts);} else {  // 达到最大尝试次数set_lock();  // 锁定账号printf("连续错误%d次,账号已锁定,请%d秒后再试。\n",MAX_ATTEMPTS, LOCK_TIME);}}}} else {  // 非法选择处理printf("非法选择!\n");log_message("非法功能选择: %d", flag);  // 记录非法选择}log_message("程序结束");  // 记录程序结束return 0;  // 正常退出
}

用户注册登录系统功能说明

代码功能概述

这段代码实现了一个完整的用户注册和登录系统,具有以下核心功能:

  1. 用户注册功能

    • 允许新用户创建账户

    • 包含用户名唯一性检查

    • 密码二次确认机制

  2. 用户登录功能

    • 验证用户凭据

    • 提供有限次数的尝试机会

    • 安全锁定机制防止暴力破解

  3. 安全保护机制

    • 连续登录失败后账号锁定(8秒)

    • 自动解锁功能

  4. 日志记录系统

    • 记录所有关键操作和事件

    • 包含时间戳的详细日志

    • 用于系统监控和故障排查

可能的标题建议

技术性标题

  1. "基于文件存储的用户认证系统实现"

  2. "C语言实现的注册登录系统(含日志功能)"

  3. "带账号锁定机制的终端用户认证程序"

功能性标题

  1. "安全用户注册与登录管理系统"

  2. "支持日志记录的终端用户认证解决方案"

  3. "防暴力破解的用户登录系统实现"

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/88128.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/88128.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/88128.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go与JS无缝协作:Goja引擎实战之错误处理最佳实践

引言&#xff1a;当Go邂逅JavaScript 在现代软件开发中&#xff0c;跨语言协作已成为提升效率的关键。想象一下&#xff1a;用Go的高性能处理核心逻辑&#xff0c;同时用JavaScript的灵活性实现动态规则——这不再是梦想。Goja&#xff0c;这个纯Go语言实现的JavaScript引擎&am…

继承与多态:面向对象编程的两大支柱

引言&#xff1a;为什么必须掌握继承与多态&#xff1f; 在Java开发中&#xff0c;继承与多态是构建可扩展、易维护系统的基石&#xff1a; 继承&#xff1a;实现代码复用&#xff0c;建立清晰的类层次结构多态&#xff1a;提升代码灵活性&#xff0c;实现"编写一次&#…

2025使用VM虚拟机安装配置Macos苹果系统下Flutter开发环境保姆级教程--上篇

前言 我们在学习Flutter开发的过程中&#xff0c;永远都跳不过去的一个问题就是如何在MAC下开发并打包Flutter工程项目&#xff0c;但MAC开发首先要解决的问题就是我们一般技术人员的电脑都是WINDOWS操作系统&#xff0c;专门配置一台MAC的话成本又是不得不考虑的因素&#xf…

250708-Svelte项目从Debian迁移到无法联网的RHEL全流程指南

&#x1f4cc; 背景 在 Debian 上使用以下命令创建了一个 Svelte 项目&#xff1a; npm install -g sv npx sv create my-svelte-demo cd my-svelte-demo npm install npm run dev现在需要将该项目迁移到一台 无法联网的 RHEL 9.4 服务器 上运行&#xff0c;出现如下报错&…

力扣 hot100 Day39

118. 杨辉三角 给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 class Solution { public:vector<vector<int>> generate(int numRows) {vector<vector<int>> res(numRows);for (int i 0; i < numRows; i) {res[i].resi…

HuggingFists: 无代码处理复杂PDF

有过使用LLM搭建RAG或其它类知识系统的朋友一定会对文档数据的复杂多样性有着深刻的理解。各行各业的磁盘中都沉睡了数年到数十年的各类文档信息&#xff0c;包括&#xff1a;Doc、Docx、PPT、PDF、XLS、PNG、JPEG等各类格式。利用LLM激活这些数据价值的首要工作就是能够正确的…

Vue 3 框架实现理念、架构与设计哲学深度解析

第一部分&#xff1a;Vue 3 的起源&#xff1a;架构演进与设计哲学 Vue 3 的诞生并非一次简单的版本迭代&#xff0c;而是一场深刻的架构革命。它的出现是前端技术演进、应用规模扩张以及对更高性能和可维护性追求的必然结果。要全面理解 Vue 3 的各项实现理念&#xff0c;必须…

SQL Server使用存储过程导出数据到Excel实现方式

在SQL Server数据库管理中,存储过程作为预编译的T-SQL语句集合,能显著提升数据操作效率与安全性。将数据导出到Excel的需求广泛存在于报表生成、数据迁移等场景。本文详细解析四种通过存储过程实现数据导出的技术方案,涵盖代码实现、适用场景及优化策略,为不同业务需求提供…

OpenGL 2. 着色器

#include <glad/glad.h> #include <GLFW/glfw3.h> #include <iostream> #include <stdexcept>// 函数声明 void framebuffer_size_callback(GLFWwindow* window, int width, int height); void processInput(GLFWwindow* window); void checkShaderCom…

【c++】容器扩容导致的类实例资源被错误释放

BUG记录 表现为新实例被存入前&#xff0c;容器内部的旧实例的析构被意外调用 因为 std::vector 在容量不足时&#xff0c;会自动扩容&#xff0c;把旧元素「搬」到新内存&#xff0c;然后析构旧内存上的那些对象。然后由于LKMotorController 类里没有正确处理移动语义&#xf…

TypeScript 集成

下面&#xff0c;我们来系统的梳理关于 Vue TypeScript 深度集成 的基本知识点&#xff1a;一、TypeScript 与 Vue 集成概述 1.1 为什么需要 TypeScript 类型安全&#xff1a;编译时类型检查&#xff0c;减少运行时错误代码智能&#xff1a;强大的IDE智能提示和自动补全可维护…

npm proxy

背景 前端项目下载依赖时经常会出现timeout的情况&#xff0c;此时有三种解决方案。 切换镜像源。 适用于对依赖版本要求不严格的情况。延长超时时间。设置npm proxy。一些生产环境对依赖版本有着严格要求&#xff0c;并且指定了依赖的下载地址&#xff08;如下图&#xff09;&…

TVS管工作原理是什么?主要的应用场景都有哪些?

什么是TVS管&#xff1f; TVS&#xff08;Transient Voltage Suppressors&#xff09;&#xff0c;即瞬态电压抑制器&#xff0c;也被称为雪崩击穿二极管&#xff0c;是一种二极管形式的高效能保护器件&#xff0c;常用来防止端口瞬间的电压冲击造成后级电路的损坏。 TVS 有单…

分布式微服务系统架构第156集:JavaPlus技术文档平台日更-Java线程池使用指南

title: java线程池使用 author: 哪吒 date: 2023-06-15点击勘误issues&#xff0c;哪吒感谢大家的阅读Java线程池使用指南1. 线程池基础使用1.1 创建线程池的方式方式一&#xff1a;使用Executors工具类&#xff08;不推荐&#xff09;// 1. 固定大小线程池 ExecutorService fi…

【最新版】点大全能版v2.6.7.1 含汇付斗拱插件+uniapp前端

一.介绍V2全能版本、独立版本全开源&#xff0c;含链动21&#xff0c;汇付斗拱​、排队免单、推三返1 &#xff0c;扶持金&#xff0c;平级奖&#xff0c;团队业绩奖&#xff0c;酒店管理&#xff0c;约车&#xff0c;餐饮等众多营销功能&#xff0c;商城系统版本号为2.6.7.1&a…

Go语言高级面试必考:切片(slice)你真的掌握了吗?

目录 1. 切片是个啥?从数组到切片的灵魂进化 数组与切片的爱恨情仇 切片的内存结构:三巨头共舞 切片的初始化方式:灵活到飞起 切片的“引用”特性:福也是祸 源码初探:切片的诞生 2. 切片三剑客:len、cap 和底层数组的三角恋 len 和 cap 的微妙关系 切片共享的秘密…

monorepo + Turborepo --- 开发应用程序

目录 配置开发任务 在 dev 之前运行设置任务 运行特定应用程序 使用终端 UI 与任务交互 监听模式 watch 将 turbo watch 与持久任务一起使用 依赖感知的持久任务 没有依赖感知的持久任务 缓存 任务输出 局限性 在 Monorepo 中开发应用程序可以解锁强大的工作流程&…

C#字符串相关库函数运用梳理总结 + 正则表达式详解

C# 字符串常用库函数总结 &#x1f539; 1. 字符串比较 方法说明示例string.Equals()比较两个字符串是否相等&#xff08;可忽略大小写&#xff09;string.Equals("abc", "ABC", StringComparison.OrdinalIgnoreCase) / !判断两个字符串是否相等/不等&quo…

投机采样(Speculative Decoding)

投机采样&#xff08;Speculative Decoding&#xff09; 是一种加速大型语言模型&#xff08;LLM&#xff09;推理的技术&#xff0c;其核心思想是通过预生成候选token序列并异步校验&#xff0c;从而减少主模型的计算量&#xff0c;同时保持生成结果的准确性。 核心思想是通过…

如何将华为手机中的照片传输到电脑

华为手机在众多手机品牌中以其出色的品质脱颖而出&#xff0c;尤其是其摄像头功能。有时&#xff0c;你可能在华为手机上积累了太多有意义的照片&#xff0c;想要将这些照片上传到电脑以释放手机存储空间。然而&#xff0c;出于用户信息安全的考虑&#xff0c;一些便捷的方法可…