摘要算法的模块

什么是摘要算法呢?摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。

摘要算法就是通过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest,目的是为了发现原始数据是否被人篡改过。

摘要算法之所以能指出数据是否被篡改过,就是因为摘要函数是一个单向函数,计算f(data)很容易,但通过digest反推data却非常困难。而且,对原始数据做一个bit的修改,都会导致计算出的摘要完全不同。

import hashlib
md5_obj = hashlib.md5()   #选择摘要算法中的md5类进行实例化,得到md5_obj
md5_obj.update(b'how to use md5 in python hashlib?') #对一个字符串进行摘要
# md5_obj.update(b'alex') #对一个字符串进行摘要
print(md5_obj.hexdigest()) #找摘要算法要结果

#一篇文章的校验

#读文件 : 一行一行拿 #转换成bytes

如果数据量很大,可以分块多次调用update(),最后计算的结果是一样的:

md5 = hashlib.md5()
md5.update('how to use md5 in ')
md5.update('python hashlib?')
print(md5.hexdigest())

MD5是最常见的摘要算法,速度很快,生成结果是固定的128 bit字节,通常用一个32位的16进制字符串表示。另一种常见的摘要算法是SHA1,调用SHA1和调用MD5完全类似:

 

校验2篇文章是不是完全一样的

# 查看某两个文件是否完全一致 —— 文件的一致性校验

#文件1

#文件2

#分别打开两个文件,一行一行读,每一行update一下 对比最终的hexdigest

 

对于用户来讲,当然不要使用过于简单的口令。但是,我们能否在程序设计上对简单口令加强保护呢?

由于常用口令的MD5值很容易被计算出来,所以,要确保存储的用户口令不是那些已经被计算出来的常用口令的MD5,这一方法通过对原始口令加一个复杂字符串来实现,俗称“加盐”:

hashlib.md5("salt".encode("utf8"))

经过Salt处理的MD5口令,只要Salt不被黑客知道,即使用户输入简单口令,也很难通过MD5反推明文口令。

但是如果有两个用户都使用了相同的简单口令比如123456,在数据库中,将存储两条相同的MD5值,这说明这两个用户的口令是一样的。有没有办法让使用相同口令的用户存储不同的MD5呢?

如果假定用户无法修改登录名,就可以通过把登录名作为Salt的一部分来计算MD5,从而实现相同口令的用户也存储不同的MD5。

摘要算法在很多地方都有广泛的应用。要注意摘要算法不是加密算法,不能用于加密(因为无法通过摘要反推明文),只能用于防篡改,但是它的单向计算特性决定了可以在不存储明文口令的情况下验证用户口令。

# 加密认证 —— 在存储密码的时候是使用密文存储的,校验密码的时候对用户的输入再做一次校验
# 加盐
# 动态加盐

普通摘要:

import hashlib
md5_obj = hashlib.md5()
md5_obj.update(b'alex3714')
print(md5_obj.hexdigest())

加盐摘要:

import hashlib
md5_obj = hashlib.md5('*!金老板'.encode('utf-8'))
md5_obj.update(b'123456')
print(md5_obj.hexdigest())

sha 算法:

import hashlib
md5_obj = hashlib.sha()
md5_obj.update(b'alex3714')
print(md5_obj.hexdigest())

SHA1的结果是160 bit字节,通常用一个40位的16进制字符串表示。比SHA1更安全的算法是SHA256和SHA512,不过越安全的算法越慢,而且摘要长度更长。

#hashilib 摘要算法的模块
# md5 sha1 sha256 sha512
# 摘要的过程 不可逆
# 能做的事儿:
    #文件的一致性检测
    #用户的加密认证
        #单纯的mg5不够安全
        #加盐处理 简单的盐可能被破解 且破解之后所有的盐都失效了
        #动态加盐

 

 

logging 模块

# log 日志
# 账单 —— 日志
# 计算器中间结果 —— 日志
# 搜索、加入购物车、购买了的东西 —— 日志
# 股票市场的用户行为 —— 日志
# 日志 就是在程序的运行过程中,人为的添加一些要打印的中间信息
# 在程序的排错、在一些行为、结果的记录

函数式简单配置

# logging

import logging
logging.debug('debug message')     #调试模式
logging.info('info message')       #信息模式
logging.warning('warning message') #警告模式 : 不会直接引发程序的崩溃,但是可能会出问题
logging.error('error message')     #错误模式 : 出错了
logging.critical('critical message') #批判模式 程序崩溃了的时候

 默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG),默认的日志格式为日志级别:Logger名称:用户输出消息。

 

必须出现但是对程序的正常运行没有影响---info 如:# 账单 —— 日志,# 搜索、加入购物车、购买了的东西 —— 日志,# 股票市场的用户行为 —— 日志

不是必须出现,但是如果有问题需要借助它的信息调试 ----debug 如;# 计算器中间结果 —— 日志

如果这样写很有可能会引发程序的一些错误的时候(不正常的形式,不会直接应发程序的崩溃,但是可能会出问题)----warning

出错了  ----error

程序崩溃了 ---critical

 

灵活配置日志级别,日志格式,输出位置:

import logging

logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S',
                    filename='test.log',
                    filemode='w')

try:
    r = input('num : ')
    int(r)
except:
    logging.error('please input a num!')

# logging 简单的配置模式

import logging

logging.basicConfig(level=logging.WARNING,  #记录的等级
                    format='[%(asctime)s]%(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S',  #时间格式
                    filename='test.log',      #日志文件
                    filemode='a')             #编辑模式

logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有:

filename:用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中。
filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
format:指定handler使用的日志显示格式。
datefmt:指定日期时间格式。
level:设置rootlogger(后边会讲解具体概念)的日志级别
stream:用指定的stream创建StreamHandler。
    可以指定输出到sys.stderr,sys.stdout或者文件(f
=open(‘test.log’,’w’)),默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。 format参数中可能用到的格式化串: %(name)s Logger的名字 %(levelno)s 数字形式的日志级别 %(levelname)s 文本形式的日志级别 %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有 %(filename)s 调用日志输出函数的模块的文件名 %(module)s 调用日志输出函数的模块名 %(funcName)s 调用日志输出函数的函数名 %(lineno)d 调用日志输出函数的语句所在的代码行 %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示 %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数 %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 %(thread)d 线程ID。可能没有 %(threadName)s 线程名。可能没有 %(process)d 进程ID。可能没有 %(message)s用户输出的消息

 

import logging

logging.basicConfig(level=logging.WARNING,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S',
                    filename='test.log',
                    filemode='w')

logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')

try:
    r = input('num : ')
    int(r)
except:
    logging.error('please input a num!')


输出到屏幕:

import logging  
logging.basicConfig(level=logging.DEBUG,  
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',  
                    datefmt='%a, %d %b %Y %H:%M:%S',)  
                    #filename='/tmp/test.log',  
                    #filemode='w')  这2行不要,输出到屏幕
  
logging.debug('debug message')  
logging.info('info message')  
logging.warning('warning message')  
logging.error('error message')  
logging.critical('critical message')

 

logger对象配置:

实例一:

# logger日志对象 ---》日志的文件句柄 ---》日志的输出格式
import logging
logger = logging.getLogger()   #实例化一个logger对象
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log', encoding='utf-8')  # 文件句柄-日志文件操作符
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') #日志输出格式
formatter2 = logging.Formatter('%(asctime)s - %(name)s  [%(levelname)s]  %(message)s') #日志输出格式
fh.setFormatter(formatter)   #文件句柄 绑 格式
logger.setLevel(logging.DEBUG)  #设置日志等级,默认是Warning
logger.addHandler(fh) #logger 绑文件句柄

sh = logging.StreamHandler()  #屏幕流对象
sh.setFormatter(formatter2)
logger.addHandler(sh)

logger.info('hello!')

 

实例二:

import logging

logger = logging.getLogger()
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log')
# 再创建一个handler,用于输出到控制台
ch = logging.StreamHandler()

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

fh.setFormatter(formatter)
ch.setFormatter(formatter)

logger.addHandler(fh) #logger对象可以添加多个fh和ch对象
logger.addHandler(ch)

logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')

#logging
# basicConfig
    # 配置简单,配了就能直接
# 对象的模式
    # 可以随意的控制往那些地方输出日志
    # 且可以分别控制输出到不同位置的格式