• day1作业:编写登录窗口一个文件实现


        思路:

        1、参考模型,这个作业我参考了linux的登录认证流程以及结合网上银行支付宝等锁定规则;

          1)认证流程参考的是Linux的登录:当你输入完用户名密码后再验证用户名是否存在用户是否被锁定,然后在验证密码是否正确,如果验证不过去只会告诉你验证失败,而不告诉你到底是用户名错误还是密码错误,增加了暴力破解的难度;

          2)关于输入错误次数的计数和锁定,我参考的是银行和支付宝的做法,也就是只关心你输错了多少次,不关心输对了多少次,也就是说输错了两次,第三次输对了,前面的计数不清零,也就是你今天输入了1000次输对了997次,只输错了3次,那对不起,依然要锁定。而且输入错误的3次不一定要连续。只要三次输入错误三次就锁定。

        2、关于计数和状态的保存我考虑还是通过文件来持久化保存,每次输入错误次数的累加和锁定都保存到文件中,这样虽然增加了文件的操作,但是保证了程序的可靠性,这样程序退出,计数依然有效。文件类型如下:

        alex sb lock 3
      tom 666 unlock 0
      geng 888 unlock 2

        其中第一列是用户名,第二列是密码,第三列是用户状态(lock代表锁定,unlock代表没有锁定),第四列是登录次数(其实,登录次数只要错误的时候登录次数加一即可,没有错误的时候不用管它)。

    代码如下:

     1 def write_file(messages,filename):
     2     """向文件中添加信息,一行一行添加信息,打开文件使用'w'格式要注意"""
     3     with open(filename,"w") as f:
     4         for key,values in messages.items():
     5             """
     6             lines = []
     7             print(key,value)
     8             lines.append(key)
     9             lines.extend(value)     #把一个列表的信息添加到另一个列表中
    10             print("lines",lines)
    11             f.write(" ".join(lines) + "
    ")
    12             """
    13             values.insert(0,key)              #由于字典的值是列表,可以直接向列表中插入元素
    14             f.write(" ".join(values) + "
    ")  #字符串拼接,字符串与列表拼接
    15 
    16 # messages = {"alex":["sb","lock","3222"],"tom":["666","unlock","0222"],"geng":["888","unlock","2222"]}
    17 # write_file(messages,"account.db")
    18 
    19 if __name__ == "__main__":
    20     active = True
    21     #程序执行的标识符,可以通过标识符来执行程序
    22     while active:
    23         username = input("请输入你的用户名(输入quit退出):")
    24         users_dict = {}     #用户字典,用于存放用户的信息,键-用户名,值-列表对应的密码,状态,次数
    25         with open("account.db","r") as obj_f:     #打开文件,读取文件信息
    26             lines = obj_f.readlines()             #按行读取文件,读取到一个列表中
    27             for line in lines:
    28                 user_list = line.strip().split()
    29                 users_dict[user_list[0]] = user_list[1:]  #把用户信息存放在一个字典中,字典的值是一个列表
    30 
    31         if username in users_dict.keys():
    32             if users_dict[username][1] == "lock":
    33                 print("您输入的用户名已经锁定,请联系管理员!")
    34                 exit()
    35             else:
    36                 while int(users_dict[username][2]) < 3:
    37                     user_pwd = input("请输入密码:")
    38                     if users_dict[username][0] == user_pwd:
    39                         print("欢迎回来,祝你生活愉快,天天OOXX!")
    40                     else:
    41                         if int(users_dict[username][2]) != 2:
    42                             print("还有%s次机会,用户将被锁定!" % (2 - int(users_dict[username][2])))
    43                         users_dict[username][2] = int(users_dict[username][2]) + 1
    44                 else:
    45                     #输入次数过多,要锁定用户
    46                     print("对不起,您输入的次数过多,你的用户名已经被锁定,请联系管理员!")
    47                     users_dict[username][1] = "lock"
    48                     users_dict[username][2] = "3"
    49                     write_file(users_dict,"account.db")
    50         elif username == "quit":
    51             exit()
    52 
    53         else:
    54             print("您输入的用户名不存在,请重新输入!")
    运行结果如下:
    请输入你的用户名(输入quit退出):tom
    请输入密码:22
    还有2次机会,用户将被锁定!
    请输入密码:22
    还有1次机会,用户将被锁定!
    请输入密码:22
    对不起,您输入的次数过多,你的用户名已经被锁定,请联系管理员!
    请输入你的用户名(输入quit退出):alex
    您输入的用户名已经锁定,请联系管理员!

        其实对文件的操作,其本质上还是对字符串列表,字典的操作,文件的操作,读取文件的方法,readlines()按行读取存放到一个列表中,使用dict(字典)记录用户信息。字符串的拼接(join)方法,(" ".join(list)),字符串与列表进行拼接,形成一个新的字符串,其实字符串的本质上在python中存储的形式就是以列表的形式存储,列表之间的拼接,list.extend(list),列表之间的拼接。

         代码说明:

        1、这里用了两个今天课程没有讲的内容:字典和函数,将用户信息以字典的方式保存是出于判断用户名是否存在的考虑,读文件的时候直接将用户名作为字典的一个key,其他的信息作为字典的value与key一一对应,这样在判断用户名是否存在只需要通过in这个成员运算符进行判断就可以了;

        2、代码的第61和62两行代码完成的就是将文件变成字典的过程。

         原创张晓宇代码实例:

    #!/usr/bin/env python3
    # coding:utf-8
    '''
    Created on: 2015年12月29日
    
    @author: 张晓宇
    
    Email: 61411916@qq.com
    
    Version: 1.0
    
    Description: 输入用户名密码,认证成功显示欢迎信息,认证失败,输错三次后锁定
    
    Help:
    '''
    import os
    # 定义用户信息写入函数,用于把用户信息写回文件
    def write_to_account_file(accounts,account_file_path):
        """accounts是一个用户信息字典,目的是把变更过的信息写入文件中"""
        account_file = open(account_file_path,"w")
        for key,val in accounts.items():
            line = []
            line.append(key)
            line.extend(val)
            print(" ".join(line))      #字符串与列表拼接,目的是实现列表中每个元素加空格生成一个字符串如a b c d格式
            account_file.write(" ".join(line) + "
    ")    #往文件中添加信息
        account_file.close()   #直接打开文件的时候一定要记得关闭文件,以免文件休息丢失
    
    
    if __name__ == '__main__':
    
        '''
        @parameters:
            account_file_path:账户文件
            password_col_num:账户文件中密码所在的列(从0开始)
            status_col_num:账户文件中账户状态所在的列(从0开始)
            error_count_num:账户文件中输入错误次数所在的列(从0开始)
            app_info:系统信息,用户启动应用后的输出
            welcome_msg:用户成功登录后的信息
        '''
        account_file_path = 'account.db'
        password_col_num = 1
        status_col_num = 2
        error_count_num = 3
        app_info = '''
        +---------------------------------+
        | Welcome to gcx system           |
        | Version:2.0                     |
        | Author:zhuzhu                   |
        +---------------------------------+
        '''
        welcome_msg = "Welcome %s,authentication is successful!"
        if os.path.exists(account_file_path):    #os.path.exists()判断文件是否存在,返回布尔值
        # 判断账户文件是否存在
            account_file = open(account_file_path,"r")
        else:
            #文件不存在,看系统是否有误
            print("Error:Account file 'account.db' is not exit,please check!")
            exit(1)
    
        #读账户文件
        accounts = {}
        for line in account_file.readlines():   #按行读取文件
            account = line.strip().split()      #清楚空格后进行分列,生成一个列表
            accounts[account[0]] = account[1:]
            """把列表中的第一个元素(用户名)当做键,用户的其他信息当做值,组成键值对存放在字典中"""
            """account[0]键,account[1:]是值"""
        account_file.close()    #关闭文件
        flag = True
        while flag:
            print(app_info)
            #输入用户名
            username = input("Username(Enter quit to exit): ").strip()
            #判断用户是否输入的为quit
            if username == "quit":
                #是则退出循环,程序结束
                break
            password = input("Password: ").strip()
            #判断用户名是否存在
            if username not in accounts.keys():
                #不存在提示错误信息并退出当前循环让用户重新输入
                print("Error:Username or Password it is error!")
                continue     #结束本次循环,让用户再次输入用户名和密码,继续执行下一次循环
            if accounts[username][status_col_num - 1] == "lock":
                #如果被锁定退出当前循环让用户重新输入
                print("Error:Account is locked.Please contact the administrator!")
                continue    #跳过本次循环,让用户重新输入进行验证,这个可以避免很多缩进,能够继续执行下一次
            #判断用户密码是否正确
            if password == accounts[username][password_col_num - 1]:
                #正确显示欢迎信息
                print(welcome_msg %username)
                break
            else:
                #用户密码不正确的情况
                #提示用户名或密码错误
                print("Error:Username or Password it is error!")
                #输入错误次数加1
                accounts[username][error_count_num - 1] = str(int(accounts[username][error_count_num - 1]) + 1)
                #判断是否已经达3次
                if int(accounts[username][error_count_num - 1 ]) == 3:
                    #如果输入错误达到3次
                    #提示账户将被锁定
                    print("Error: This account will be locked,Please contact the administrator!System will be exit!")
                    #将用户状态改为lock并写入文件
                    accounts[username][status_col_num - 1] == "lock"
                    write_to_account_file(accounts,account_file_path)
                    break
                write_to_account_file(accounts,account_file_path)

        上面代码中亮点:

        (1)continue:结束本次循环,continue后面的代码都不执行,达到重新让用户输入的目的,很多网页都是让用户一直输入,知道用户要么选择注册,要么关掉网页;

        (2)文档的规范性比较好,有解释;

        (3)文件就是一行一行读,然后一行一行写入文件,修改的过程中要用到列表和字典的知识;

      (4)" ".join(list)字符串与列表的拼接,生成新的字符串;

        (5)split()字符串的分割;extend()列表之间的拼接。

  • 相关阅读:
    产生6位的随机码
    用户输入注册的小程序
    进度条的小程序
    文件的相关操作---读写与修改
    字符串分割(C++) 转载
    C++ Stream与编码转换
    wxWidgets界面设计工具DialogBlocks(转载)
    WIN32窗口模板
    WTL对话框应用程序响应键盘消息
    常用网站
  • 原文地址:https://www.cnblogs.com/gengcx/p/6938413.html
Copyright © 2020-2023  润新知