目录

前言

项目说明

代码实现

app.py

 common.py


前言

打基础,学Web安全还是得先落实到开发学习上。

接下来将以简单小项目为单位锻炼自己的实操能力,计划寒假前完成python的部分,寒假专注java部分。这期间的博客主要记录开发学习内容,磨刀不误砍柴工。

项目说明

通常情况下,如果利用文本文件来保存数据,有三种数据可供使用:
1.CSV文件
2.XML文件
3.JSON文件(频率最高)

这里我们选用第一种CSV文件

简单说明功能的实现:

要求一
1.用户注册时必须要输入用户名、密码、手机号码,针对用户的输入必须验证。
2.用户名的规则:只能是大小写字母或数字,且不能以数字开头,长度为5~12位。
3.密码的规则:密码必须且只能由大小写字母和数字组成,长度为6~15位。
4.手机号码的规则:按照标准的中国手机号码规则进行校验。
5.如果校验成功,则允许用户注册,注册信息保存于列表或字典中,否则要求用户继续输入。

要求二
1.基于命令行给用户设定一个菜单,让用户可以决定下一步干什么。
2.支持多用户注册,注册时,如果已经存在的用户名不能注册。
3.将注册的用户名密码电话等信息,保存在文本文件中(CSV文件)。
4.实现用户的登录功能,用于登录验证。
5.在使用CSV保存用户数据的情况下,让用户可以修改密码(输入用户名、旧密码、新密码)

代码实现

先创建一个exercise包,自动生成__init__.py,包里放app.py(主程序),common.py(通用函数模块),userpass.csv(用于储存读写数据的CSV文件)

【Python】基于CSV文件读写的注册登陆改密功能程序实现-LMLPHP

app.py

from exercise.common import *


def input_username():
    # global username
    username=input("请输入用户名: ")
    if check_username(username):
        if check_user_exists(username):
            print("用户名已存在.")
            return input_username()
        else:
            print("用户名正确.")
            return username
    else:
        print("用户名错误.")
        return input_username()

def input_password():
    # global password
    password=input("请输入密码: ")
    if check_password(password):
        print("密码正确.")
        return password
    else:
        print("密码错误.")
        return input_password()

def input_phone():
    # global phone
    phone=input("请输入手机号: ")
    if check_phone(phone):
        print("手机号正确.")
        return phone
    else:
        print("手机号错误.")
        return input_phone()


def do_reg():
    username=input_username()
    password=input_password()
    phone=input_phone()
    with open('./userpass.csv',mode='a') as f:
        f.write(f"\n{username},{password},{phone}")
        print("恭喜你,注册成功.")
        draw_menu()

def do_login():
    username=input("请输入用户名:")
    password=input("请输入密码:")
    user=check_get_user(username)
    if user is None:
        print("用户名不存在.")
        exit(0)
    elif user['password']==password:
        print("用户名密码正确,登录成功.")
    else:
        print("登录失败.")
    draw_menu()

def do_change():
    username = input("请输入用户名:")
    password = input("请输入密码:")
    user = check_get_user(username)
    if user is None:
        print("用户名不存在.")
        draw_menu()
    elif user['password']==password:
        newpass=input("请输入新密码:")
        change_password(username,newpass)
    else:
        print("旧密码验证不通过.")




def draw_menu():
    print("======== 请选择菜单项 ========")
    print("1、注册 2、登录 3、修改密码 4、退出")
    option=input("请选择菜单项:[1,2,3,4]:")
    if option=='1':
        do_reg()
    elif option=='2':
        do_login()
    elif option=='3':
        do_change()
    elif option=='4':
        exit(0)
    else:
        print("请输入正确的菜单编号.")
        draw_menu()



if __name__ == '__main__':
    draw_menu()

 common.py

import re
'''
长度的判断5-12位,使用len函数进行判断
不能以数字开头:username[0]不能是0-9的范围
判断只能是大小写或数字:
返回值:True:用户名正确,False:用户名错误
'''
def check_username(username):
    if len(username) < 5 or len(username) > 12:
        return False
    if username[0] >= '0' and username[0] <= '9':
        return False
    for char in username:
        if not (ord(char) in range(65,91) or ord(char) in range(97,123) or ord(char) in range(48,58)):
            return False
    return True

'''
检查密码:由大写、小写和数字构成,且必须是6-15位
只要确保密码中至少有1位是大写,至少有1位是小写,至少有1位是数字
'''
def check_password(password):
    if len(password)<6 or len(password)>15:
        return False
    lower,upper,digit,other=0,0,0,0
    for char in password:
        if char>='A' and char<='Z':
            upper+=1
        elif char>='0' and char<='9':
            digit+=1
        elif char>='a' and char<='z':
            lower+=1
        else:
            other+=1
    if upper<1 or lower<1 or digit<1 or other>0:
        return False
    return True

def check_phone(phone):
    pattern = "^1[3-9]\d{9}$"
    if re.match(pattern,phone):
        return True
    else:
        return False

#读取CSV,并动态将第一行作为字典的key,返回[{},{}]的格式
def read_csv(csvfile,has_column=True):
    with open(csvfile) as f:
        line_list=f.readlines()
    if not has_column:
        raise Exception("CSV文件必须要使用第一行作为列名")
    key_list=line_list[0].strip().split(',')
    list=[]
    for i in range(1,len(line_list)):
        temp_list=line_list[i].strip().split(',')
        dict={}
        for j in range(len(key_list)):
            dict[key_list[j]]=temp_list[j]
        list.append(dict)
    return list

#读取CSV文件,并检查用户名是否存在
def check_user_exists(username):
    user_list=read_csv('./userpass.csv')
    for user in user_list:
        if user['username']==username:
            return True
    return False

#根据用户名取得CSV文件中对应的一行用户数据,以字典的形式返回
def check_get_user(username):
    user_list=read_csv('./userpass.csv')
    for user in user_list:
        if user['username']==username:
            return user
    return None

#修改用户的密码,修改一个CSV文件中的某一行中的某一列,不能直接修改(Python中不存在文件内容部分修改的操作)
#将CSV整体读入到内存中,形成列表+字典,然后修改字典的某一项,再整体覆盖写入到CSV
def change_password(username,newpass):
    csv_list=read_csv('./userpass.csv')
    for user in csv_list:
        if user['username']==username:
            index=csv_list.index(user)
            break
    csv_list[index]['password']=newpass
    #将列表+字典还原成行+逗号分割数据
    with open('./userpass.csv',mode='w') as f:
        f.write("username,password,phone\n")
        for user in csv_list:
            line=f"{user['username']},{user['password']},{user['phone']}\n"
            f.write(line)




#全自动的单元测试代码,编写一个测试驱动程序
def test_driver(func,expect,*args):
    actual=func(*args)
    if actual==expect:
        print("测试 %s:成功" %func.__name__)
    else:
        print("测试 %s: 失败" %func.__name__)


if __name__=='__main__':
    pass
# test_driver(check_password,True,'123456789')

userpass.csv

username,password,phone
czr,czr123,13112345678
admin,admin123,13212345678
root,root123,13312345678
hack,hack123,13412345678
Z3r4y,Z3r4y123,13123456789
CubicU,CubicU123,13123456789
suibian,Asuibian123,13123456789
12-20 22:37