代码
/* 作业增强版注册登录系统 - 带日志和安全性增强功能 */
#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; // 正常退出
}
用户注册登录系统功能说明
代码功能概述
这段代码实现了一个完整的用户注册和登录系统,具有以下核心功能:
用户注册功能
允许新用户创建账户
包含用户名唯一性检查
密码二次确认机制
用户登录功能
验证用户凭据
提供有限次数的尝试机会
安全锁定机制防止暴力破解
安全保护机制
连续登录失败后账号锁定(8秒)
自动解锁功能
日志记录系统
记录所有关键操作和事件
包含时间戳的详细日志
用于系统监控和故障排查
可能的标题建议
技术性标题
"基于文件存储的用户认证系统实现"
"C语言实现的注册登录系统(含日志功能)"
"带账号锁定机制的终端用户认证程序"
功能性标题
"安全用户注册与登录管理系统"
"支持日志记录的终端用户认证解决方案"
"防暴力破解的用户登录系统实现"