图形化验证码生成和验证

功能介绍

在使用用户名和密码登录功能时,需要填写验证码,验证码是以图形化的方式进行获取和展示的。

验证码使用原理

验证码的使用流程和原理为:在服务器端负责生成图形化验证码,并以数据流的形式供前端访问获取,同时将生成的验证码存储到全局的缓存中,在本案例中,我们使用redis作为全局缓存,并设置缓存失效时间。当用户使用用户名和密码进行登录时,进行验证码验证。验证通过即可继续进行登录。

验证码库安装

借助开源的验证码工具库可以生成验证码。

首先,安装开源的验证码生成库:

go get -u github.com/mojocn/base64Captcha
go get github.com/mojocn/base64Captcha@v1.2.2
验证码代码示例

在下载后的base64Captcha库的目录中,可以看到有_example和_example_redis两个目录。第一个example是用于演示生成验证码和验证码的示例代码。

按照示例代码的说明,运行程序并在浏览器进行端口访问:

go run main.go
//浏览器中访问:http://localhost:8777

如下图所示:

通过自定义配置,可以选择不同的生成验证码的参数,并刷新验证码,同时还可以对验证码进行验证。

通过exmaple目录下的main.go程序可以看到生成验证码和验证验证码的逻辑,此处不再赘述。

项目集成验证码生成和Redis缓存

通常来说,验证码都是有一定的实效性的,过期验证码也就无效了。

因此,我们考虑在项目中引入Redis作为数据缓存。当验证码生成后,将验证码存放在Redis中,并根据配置文件对Redis进行设置。

安装go-redis库

在项目中使用redis,需要安装go-redis库,可以在https://github.com/go-redis/redis中查看如何下载go-redis和配置。

增加Redis配置

在配置文件app.json中新增redis配置:

"redis_config": {
"addr": "127.0.0.1",
"port": "6379",
"password": "",
"db": 0
}

同时,新增RedisConfig结构体定义,如下所示:

type RedisConfig struct {
Addr string `json:"addr"`
Port string `json:"port"`
Password string `json:"password"`
Db int `json:"db"`
}
Redis初始化操

进行了redis配置以后,需要对redis进行初始化。可以封装redis初始化操作函数如下所示:

type RedisStore struct {
redisClient *redis.Client
} var Redis *redis.Client func InitRediStore() *RedisStore {
config := GetConfig().RedistConfig Redis = redis.NewClient(&redis.Options{
Addr: config.Addr + ":" + config.Port,
Password: config.Password,
DB: config.Db,
}) customeStore := &RedisStore{Redis}
base64Captcha.SetCustomStore(customeStore) return customeStore
}

同时,为customeStore提供Set和Get两个方法,如下所示:

func (cs *RedisStore) Set(id string, value string) {
err := cs.redisClient.Set(id, value, time.Minute*2).Err()
if err != nil {
log.Println(err.Error())
}
} func (cs *RedisStore) Get(id string, clear bool) string {
val, err := cs.redisClient.Get(id).Result()
if err != nil {
toolbox.Error(err.Error())
return ""
}
if clear {
err := cs.redisClient.Del(id).Err()
if err != nil {
toolbox.Error(err.Error())
return ""
}
}
return val
}

对Redis进行初始化和定义完成以后,需要在main中调用一下初始化操作InitRediStore:

func main(){
...
//Redis配置初始化
toolbox.InitRediStore()
...
}
验证码生成和验证

本项目中采用的验证码的生成库支持三种验证码,分别是:audio,character和digit。我们选择character类型。

定义Captcha.go文件,实现验证码的生成和验证码函数的定义。在进行验证码生成时,默认提供验证码的配置,并生成验证码后返回给客户端浏览器。如下是生成验证码的函数定义:

//生成验证码
func GenerateCaptchaHandler(ctx *gin.Context) {
//图形验证码的默认配置
parameters := base64Captcha.ConfigCharacter{
Height: 60,
Width: 240,
Mode: 3,
ComplexOfNoiseText: 0,
ComplexOfNoiseDot: 0,
IsUseSimpleFont: true,
IsShowHollowLine: false,
IsShowNoiseDot: false,
IsShowNoiseText: false,
IsShowSlimeLine: false,
IsShowSineLine: false,
CaptchaLen: 4,
BgColor: &color.RGBA{
R: 3,
G: 102,
B: 214,
A: 254,
},
} captchaId, captcaInterfaceInstance := base64Captcha.GenerateCaptcha("", parameters)
base64blob := base64Captcha.CaptchaWriteToBase64Encoding(captcaInterfaceInstance) captchaResult := CaptchaResult{Id: captchaId, Base64Blob: base64blob} // 设置json响应
tool.Success(ctx, map[string]interface{}{
"captcha_result": captchaResult,
})
}
验证码接口解析

图形化验证码是用户名和密码登录功能的数据,属于Member模块。因此在MemberController中增加获取验证码的接口解析,如下:

func (mc *MemberController) Router(engine *gin.Engine){
//获取验证码
engine.GET("/api/captcha", mc.captcha)
}

测试结果如下,能够正常获取到数据:

验证码的验证

同理,可以对客户端提交的验证码进行验证,具体实现逻辑如下:

//验证验证码是否正确
func CaptchaVerify(r *http.Request) bool { var captchaResult CaptchaResult
//接收客户端发送来的请求参数
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&captchaResult)
if err != nil {
log.Println(err)
}
defer r.Body.Close() //比较图像验证码
verifyResult := base64Captcha.VerifyCaptcha(captchaResult.Id, captchaResult.VertifyValue) return verifyResult
}

用户名密码登录功能开发

功能介绍

上节课已经完成了验证码的生成,本节课来开发用户名、密码和验证码登录功能。

接口和参数解析定义

用户名和密码的登录接口为:

/api/login_pwd

接口请求类型为POST,接口参数有三个:name,pwd,captcha。其中:captcha为验证码。

定义登录参数结构体LoginParam:

//用户名,密码和验证码登录
type LoginParam struct {
Name string `json:"name"` //用户名
Password string `json:"pwd"` //密码
Id string `json:"id"`// captchaId 验证码ID
Value string `json:"value"` //验证码
}
逻辑控制层实现登录流程控制
方法解析

在MemberController.go文件中,编写方法用于处理用户名密码登录的解析方法如下所示:

func (mc *MemberController) Router(engine *gin.Engine){
engine.POST("/api/login_pwd", mc.nameLogin)
}

登录流程编程实现

定义新的func并命名为nameLogin,实现登录流程逻辑控制:

//用户名、密码登录
func (mc *MemberController) nameLogin(context *gin.Context) { //1、登录参数解析
var loginParam param.LoginParam err := toolbox.Decode(context.Request.Body, &loginParam)
if err != nil {
toolbox.Failed(context, "参数解析失败")
return
} //2、验证验证码
service := impl.NewMemberService()
validate := toolbox.CaptchaVerify(loginParam.Id, loginParam.Value)
fmt.Println(validate)
if !validate {
toolbox.ValidateFailed(context, "验证码不正确, 请重新验证 ")
return
} //3、登录
member := service.Login(loginParam.Name, loginParam.Password)
if member.Id == 0 {
toolbox.Failed(context, "登录失败")
return
}
toolbox.Success(context, &member)
}

在控制层的nameLogin方法中,主要有3个逻辑处理:

  • 1、通过*gin.Context解析请求登录请求携带的参数。

  • 2、从携带的参数中得到提交的验证码数据,调用验证码判断验证码方法对验证码进行判断。验证码验证失败或者验证码失效,直接返回登录失败信息。

  • 3、使用用户名、密码参数进行登录,判断登录结果。如果登录成功,返回用户登录信息,否则返回登录失败。

Service层实现

在功能服务层的MemberService文件中,定义和实现用户名密码登录的Login方法。详细实现如下:

//用户登录: 如果没有登录过,自动进行登录
func (msi *MemberServiceImpl) Login(name string, password string) *model.Member { dao := impl.NewMemberDao() //1、先查询是否已经存在该用户
member := dao.Query(name, password)
if member.Id != 0 {
return member
} user := model.Member{}
user.UserName = name
user.Password = toolbox.EncoderSha256(password)
user.RegisterTime = time.Now().Unix() result := dao.InsertMember(user)
user.Id = result
return &user
}

在service层的Login方法中,分为两步逻辑判断:

  • 1、先查询是否已经存在该用户,如果该用于已经存在,则直接将查询到的用户信息返回。

  • 2、如果用户不存在,将用户信息作为新记录保存到数据库中,新增一条记录。并返回用户信息。

最后,涉及到操作数据库的两个方法分别是:Query和InsertMember方法。InsertMember方法之前已经编写过,只需要重新编写一个Query方法即可,Query方法实现如下所示:

//根据用户名和密码查询用户记录
func (mdi *MemberDaoImpl) Query(name string, password string) *model.Member {
var member model.Member password = toolbox.EncoderSha256(password) _, err := mdi.Where(" user_name = ? and password = ? ", name, password).Get(&member)
if err != nil {
toolbox.Error(err.Error())
return nil
} return &member
}

04 . Go+Vue开发一个线上外卖应用(用户名密码和图形验证码)的更多相关文章

  1. 01 . Go之Gin+Vue开发一个线上外卖应用

    项目介绍 我们将开始使用Gin框架开发一个api项目,我们起名为:云餐厅.如同饿了么,美团外卖等生活服务类应用一样,云餐厅是一个线上的外卖应用,应用的用户可以在线浏览商家,商品并下单. 该项目分为客户 ...

  2. 03 . Gin+Vue开发一个线上外卖应用(用户数据创建,插入,跨域处理)

    功能和背景介绍 在项目的登录功能中,如果在登录时发现用户名和密码在用户表中不存在,会自动将用户名和密码保存在用户表中,创建一个新的用户. 因此,除了使用手机号和验证码登录以外,还支持使用用户名.密码进 ...

  3. 05 . Go+Vue开发一个线上外卖应用(Session集成及修改用户头像到Fastdfs)

    用户头像上传 功能介绍 在用户中心中,允许用户更换自己的头像.因此,我们开发上传一张图片到服务器,并保存成为用户的头像. 接口解析 在用户模块的控制器MemberController中,解析头像上传的 ...

  4. 02 . 02 . Go之Gin+Vue开发一个线上外卖应用(集成第三方发送短信和xorm生成存储数据库表)

    集成第三方发送短信 介绍 用户登录 用户登录有两种方式: 短信登录,密码登录 短信登录是使用手机号和验证码进行登录 短信平台 很多云平台,比如阿里云,腾讯云,七牛云等云厂商,向程序开发者提供了短信验证 ...

  5. 用vue开发一个app(4,一个久等了的文章)H5直播平台登录注册(1)

    我上一篇关于vue的文章和这一篇时间隔了有点久了.最近终于写完了. 因为我一直想写个有点实绩的东西,而不是随便写一个教程一样东西.结合最近在项目中学到的经验和我的一点创意. 首先介绍下这是个什么! H ...

  6. 用Vue开发一个实时性时间转换功能,看这篇文章就够了

    前言 最近有一个说法,如果你看见某个网站的某个功能,你就大概能猜出背后的业务逻辑是怎么样的,以及你能动手开发一个一毛一样的功能,那么你的前端技能算是进阶中高级水平了.比如咱们今天要聊的这个话题:如何用 ...

  7. vue开发小结(上)

    前言: 18年年底,就一个字,忙,貌似一到年底哪个公司都在冲业绩,包括我们自己开发自己公司的项目也一样得加把劲.自从18年年初立了个flag17年年终总结——走过2017,迎来2018Flag到现在又 ...

  8. vue本地和线上环境(域名)配置

    vue本身为运行脚手架项目自家搭载了一个nodejs后台环境,本地可通过proxyTable来处理跨域问题,但是上线(或生产环境)之后改域名真是一件麻烦的事情,所以进行一些配置. config/ind ...

  9. webpack中devtool的配置方案[开发模式]---[线上模式]

    // 开发模式下 module.exports = { mode: 'development', devtool: 'cheap-module-eval-source-map' } // 线上模式下 ...

随机推荐

  1. Python-__init__ 和 __new__区别和原理

    __init__ 和 __new__区别 1. 从传递参数角度看,__init__第一个参数是实例本身, __new__传递的是类本身 2. 从执行顺序角度看,__new__方法执行在 __init_ ...

  2. JS寄快递地址智能解析

    JS寄快递地址智能解析--2020年7月15日 去年做了些前端内容,最近在整理一些稍微有点用的内容,比如智能解析地址,用户只要输入:张三1351111111江苏省扬州市广陵区XX小区X楼xxx室,就能 ...

  3. 大话Python类语义

    类 物以类聚,人以群分,就是相同特征的人和事物会自动聚集在一起,核心驱动点就是具有相同特征或相类似的特征,我们把具有相同特征或相似特征的事物放在一起,被称为分类,把分类依据的特征称为类属性 计算机中分 ...

  4. 065 01 Android 零基础入门 01 Java基础语法 08 Java方法 02 带参无返回值方法

    065 01 Android 零基础入门 01 Java基础语法 08 Java方法 03 带参无返回值方法 本文知识点:带参无返回值方法 说明:因为时间紧张,本人写博客过程中只是对知识点的关键步骤进 ...

  5. Java知识系统回顾整理01基础03变量05变量命名规则

    一.命名规则 变量命名只能使用字母 .数字. $. _ 变量第一个字符 只能使用: 字母. $. _ 变量第一个字符 不能使用数字 注:_ 是下划线,不是-减号或者-- 破折号 int a= 5; i ...

  6. 00 你的第一个C语言程序

    C语言简介 C 语言是一种通用的.面向过程式的计算机程序设计语言,即编程语言. 为移植和开发 UNIX 操作系统,丹尼斯·里奇于1972年在贝尔电话实验室设计开发了 C 语言的第一个版本. C 语言同 ...

  7. MCU(Micro Control Unit)中文名称为微控制单元

    参考:http://www.elecfans.com/dianzichangshi/mcu.html 什么是mcu_mcu是什么意思 标签:MCU(471)单片机(3098)微控制器(503) MCU ...

  8. lens distortion

    来源:http://michel.thoby.free.fr/Fisheye_history_short/International_Standards_about_Distortion.html H ...

  9. vue中解决chrome浏览器自动播放音频 和MP3语音打包到线上

    一.vue中解决chrome浏览器自动播放音频 需求 有新订单的时候,页面自动语音提示和弹出提示框: 问题 chrome浏览器在18年4月起,就在桌面浏览器全面禁止了音视频的自动播放功能.严格地来说, ...

  10. 介绍了ASP。净样板

    下载sample application (or see on Github) 内容 问题介绍什么是ASP.NET样板文件NET Boilerplate不是开始创建空的web应用程序从模板域层 关于名 ...