Bytes-Golang-包详解之-Bytes.Buffer-中 (byte数据类型)
上篇文章具体解说了一次性性明码OTP相关的常识,基于时期的一次性性明码TOTP是OTP的一种成功方式。这种方法的优势是不依赖网络,因此即使在没有网络的状况下,用户也可以生成明码。所以这种方式被许多盛行的网站经常使用到双因子或多因子认证中,包含、、Facebook和Salesforce等等。
由于TOTP是规范化的协定并且被宽泛驳回,所以有很多对应的移动运行或许web运行成功,被称为身份验证器运行,例如GoogleAuthenticator、MicrosoftAuthenticator等。Golang也有很多低劣的三方库可以协助咱们极速成功TOTP的服务端成功,其中比拟有代表性的是pquerna/otp库,接上去就经常使用这个库来展示一下TOTP的服务端成功流程。
为用户生成TOTPKey
用户开启双因子认证时,为用户生成TOTPKey,用于生成TOTP明码。将这个明码保留在数据库或许秘钥治理系统中,生成key的关键代码如下:
key,err:=totp.Generate(totp.GenerateOpts{Issuer:"Github",AccountName:"user@example.com",Period:30,Digits:otp.DigitsSix,Algorithm:otp.AlgorithmSHA1,})
这几个参数的意思如下:
把密钥和明码生成规定分享给用户
通常是将秘钥和明码规定信息以二维码的方式展现给用户,用户经常使用身份验证器运行扫描二维码保留相关信息并且生成明码。二维码中的内容格局普通如下:
为用户提供复原码RecoveryCodes
生成复原码RecoveryCodes(经常使用随机生成的字符串即可)存储到数据库或许秘钥治理系统中。当用户不能访问自己的TOTP设备(例如将TOTP运行中的TOTP秘钥删除了、将TOTP运行卸载了、手机失落了等)时,就无法登录自己的帐户了。由于这种状况比拟经常出现,所以很多网站都会给用户提供备份代码或复原代码,并且每个只能经常使用一次性,可以暂时用来替代TOTP明码。
校验用户输入的TOTP明码
用户再次登录后,触发双因子认证,要求用户输入TOTP明码,服务端测验这个明码。校验的关键代码如下:
//验证一次性性明码isValid:=totp.Validate(passcode,key.Secret())
模拟生成密钥、校验明码的代码
packagemnimport("fmt""time""github.com/pquerna/otp""github.com/pquerna/otp/totp")funcmain(){//生成密钥key,err:=totp.Generate(totp.GenerateOpts{Issuer:"Github",AccountName:"user@example.com",Period:30,Digits:otp.DigitsSix,Algorithm:otp.AlgorithmSHA1,})iferr!=nil{panic(err)}fmt.Println("SecretURL:",key.URL())//模拟生成一个一次性性明码now:=time.Now()passcode,err:=totp.GenerateCode(key.Secret(),now)iferr!=nil{panic(err)}//验证一次性性明码valid:=totp.Validate(passcode,key.Secret())ifvalid{fmt.Println("Validpasscode!")}else{fmt.Println("Invalidpasscode!")}}
golang 分配的数组什么时候回收
结构体与[]byte不能直接转化,可以通过gob来转换。 编码时如下,假设默认的结构体为datafunc Encode(data interface{}) ([]byte, error) {buf := (nil)enc := (buf)err := (data)if err != nil {return nil, err}return (), nil}解码时如下,data为需要解码的字节数组,to为相应的接收结构体,记住to的结构体结构应与被编码的data相一致,解码后内容保存在to里面,直接使用to即可func Decode(data []byte, to interface{}) error {buf := (data)dec := (buf)return (to)}使用的时候:b, err := Encode(data)if err != nil { //错误处理 }if err := Decode(b, &to); err != nil {//错误处理}
go语言string之Buffer与Builder
操作字符串离不开字符串的拼接,但是Go中string是只读类型,大量字符串的拼接会造成性能问题。 拼接字符串,无外乎四种方式,采用“+”,“()”,, 上面我们创建10万字符串拼接的测试,可以发现,的性能最好,约是“+”的1000倍级别。 这是由于string是不可修改的,所以在使用“+”进行拼接字符串,每次都会产生申请空间,拼接,复制等操作,数据量大的情况下非常消耗资源和性能。 而采用Buffer等方式,都是预先计算拼接字符串数组的总长度(如果可以知道长度),申请空间,底层是slice数组,可以以append的形式向后进行追加。 最后在转换为字符串。 这申请了不断申请空间的操作,也减少了空间的使用和拷贝的次数,自然性能也高不少。 是一个缓冲byte类型的缓冲器存放着都是byte 是一个变长的 buffer,具有 Read 和Write 方法。 Buffer 的 零值 是一个 空的 buffer,但是可以使用,底层就是一个 []byte, 字节切片。 向Buffer中写数据,可以看出Buffer中有个Grow函数用于对切片进行扩容。 从Buffer中读取数据 的方法和的方法的命名几乎一致。 但实现并不一致,Builder的Write方法直接将字符拼接slice数组后。 其没有提供read方法,但提供了方式 Reader 结构: Buffer: Builder: 可以看出Buffer和Builder底层都是采用[]byte数组进行装载数据。 先来说说Buffer: 创建好Buffer是一个empty的,off 用于指向读写的尾部。 在写的时候,先判断当前写入字符串长度是否大于Buffer的容量,如果大于就调用grow进行扩容,扩容申请的长度为当前写入字符串的长度。 如果当前写入字符串长度小于最小字节长度64,直接创建64长度的[]byte数组。 如果申请的长度小于二分之一总容量减去当前字符总长度,说明存在很大一部分被使用但已读,可以将未读的数据滑动到数组头。 如果容量不足,扩展2*c + n 。 其String()方法就是将字节数组强转为string Builder是如何实现的。 Builder采用append的方式向字节数组后添加字符串。 从上面可以看出,[]byte的内存大小也是以倍数进行申请的,初始大小为 0,第一次为大于当前申请的最大 2 的指数,不够进行翻倍. 可以看出如果旧容量小于1024进行翻倍,否则扩展四分之一。 (2048 byte 后,申请策略的调整)。 其次String()方法与Buffer的string方法也有明显区别。 Buffer的string是一种强转,我们知道在强转的时候是需要进行申请空间,并拷贝的。 而Builder只是指针的转换。 这里我们解析一下 *(*string)((&)) 这个语句的意思。 先来了解下 的用法。 也就是说, 可以转换为任意类型,那么意味着,通过媒介,程序绕过类型系统,进行地址转换而不是拷贝。 即*A => Pointer => *B 就像上面例子一样,将字节数组转为类型,再转为string类型,s和b中内容一样,修改b,s也变了,说明b和s是同一个地址。 但是对s重新赋值后,意味着s的地址指向了“WORLD”,它们所使用的内存空间不同了,所以s改变后,b并不会改变。 所以他们的区别就在于 是重新申请了一块空间,存放生成的string变量, 而直接将底层的[]byte转换成了string类型返回了回来,去掉了申请空间的操作。
免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。