代碼
/* 作業增強版注冊登錄系統 - 帶日志和安全性增強功能 */
#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語言實現的注冊登錄系統(含日志功能)"
"帶賬號鎖定機制的終端用戶認證程序"
功能性標題
"安全用戶注冊與登錄管理系統"
"支持日志記錄的終端用戶認證解決方案"
"防暴力破解的用戶登錄系統實現"