Go+Vue开发一个线上外卖应用的流程(用户名密码和图形验证码)

图形化验证码生成和验证

功能介绍

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

验证码使用原理

验证码的使用流程和原理为:在服务器端负责生成图形化验证码,并以数据流的形式供前端访问获取,同时将生成的验证码存储到全局的缓存中,在本案例中,我们使用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
}

到此这篇关于Go+Vue开发一个线上外卖应用(用户名密码和图形验证码)的文章就介绍到这了,更多相关Go线上外卖内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 使用django和vue进行数据交互的方法步骤

    一.前端请求的封装 1.将请求地址封装起来,以便日后修改,在src/assets/js目录下创建getPath.js文件 export default function getUrl(str) { let url = 'http://localhost:8000/' + str; return url; } 2.在同一个目录下创建axios.js文件 我的前端数据交互使用的模块使用的是axios import axios from 'axios' import getUrl from './ge

  • Python Django Vue 项目创建过程详解

    1.创建项目 打开pycharm 终端,输入如下,创建项目 # 进入pycharm 项目目录下 cd pyWeb django-admin startproject pyweb_dome # pyweb_dome 是django项目名称 2.创建应用 # 进入项目根目录 pyweb_dome 下 cd pyweb_dome python manage.py startapp webserver # webserver 为应用名 3.创建前端项目 使用vue-cli在根目录创建一个名称叫[fron

  • django和vue实现数据交互的方法

    我使用的是jQuery的ajax与django进行数据交互,遇到的问题是django的csrf 传输数据的方法如下: $(function() { $.ajax({ url: 'account/register', type: 'post', dataType:'json', data: $('#form1').serialize(), success: function (result) { console.log(result); if (result) { alert("result&qu

  • 小程序外卖订单界面的示例代码

    1.效果界面 2.涉及功能 *左侧商品类型.右侧商品可以相互控制: *商品列表加减及购物车商品加减icon消失.显示: *商品每一次加减,页面视图变化(数量.价格变化.购物车置灰): 3.贴上所有代码 1.wxml <view class="container"> <view class="index-cont"> <!-- 左边类型 --> <view class="index-left"> &l

  • Go+Vue开发一个线上外卖应用的流程(用户名密码和图形验证码)

    图形化验证码生成和验证 功能介绍 在使用用户名和密码登录功能时,需要填写验证码,验证码是以图形化的方式进行获取和展示的. 验证码使用原理 验证码的使用流程和原理为:在服务器端负责生成图形化验证码,并以数据流的形式供前端访问获取,同时将生成的验证码存储到全局的缓存中,在本案例中,我们使用redis作为全局缓存,并设置缓存失效时间.当用户使用用户名和密码进行登录时,进行验证码验证.验证通过即可继续进行登录. 验证码库安装 借助开源的验证码工具库可以生成验证码. 首先,安装开源的验证码生成库: go

  • vue 接口请求地址前缀本地开发和线上开发设置方式

    开发环境 config/dev.env.js 'use strict' const merge = require('webpack-merge') const prodEnv = require('./dev.env') module.exports = merge(prodEnv, { NODE_ENV: '"development"', API_ROOT: '"https://www.dev.com"' //本地请求前缀 }) 线上开发环境 config/pr

  • VUE开发一个图片轮播的组件示例代码

    本人刚学习vue,用vue做了个图片轮播,下面我来记录一下,有需要了解VUE开发一个图片轮播的组件的朋友可参考.希望此文章对各位有所帮助. 完成效果图如下: vue开发的思路主要是数据绑定,代码如下: <template> <div ref="root" style="user-select: none;-webkit-user-select: none;overflow: hidden"> <div class="slide

  • 使用Vue开发一个实时性时间转换指令

    前言 最近有一个说法,如果你看见某个网站的某个功能,你就大概能猜出背后的业务逻辑是怎么样的,以及你能动手开发一个一毛一样的功能,那么你的前端技能算是进阶中高级水平了.比如咱们今天要聊的这个话题:如何用Vue开发一个实时性的时间转换指令? 接下来正文从这开始~ 如上图所示(我是截取的某技术社区首页的部分页面),大家看到用红色边框勾选中的时间文字了吧.很多网站发布动态的时候,都会有一个相对本机时间转换后的相对时间.那你知道这个功能实现的背后原理是什么吗?如果有兴趣的,请备好瓜子,茶水,继续往下读.

  • Vue开发之封装上传文件组件与用法示例

    本文实例讲述了Vue开发之封装上传文件组件与用法.分享给大家供大家参考,具体如下: 使用elementui的 el-upload插件实现图片上传组件 每个项目存在一定的特殊性,所以数据的处理会不同 pictureupload.vue: <template> <div class="pictureupload"> <el-upload :action="baseUrl + '/api/public/image'" list-type=&q

  • java排查一个线上死循环cpu暴涨的过程分析

    问题,打一个页面cpu暴涨,打开一次就涨100%,一会系统就卡的不行了. 排查方法,因为是线上的linux,没有用jvm监控工具rim链接上去. 只好用命令排查: top cpu排序,一个java进程cpu到500%了,什么鬼..... 查到对应java进程 jps || ps -aux | grep 端口 pid=13455 查看进程中线程使用情况 T排序 查看cpu占用time最高的线程编号 top -Hp 13455 有个线程9877 的时间一直在爆涨 获取线程十六进制地址9877 (十六

  • vue 开发一个按钮组件的示例代码

    最近面试,被问到一个题目,vue做一个按钮组件: 当时只是说了一下思路,回来就附上代码. 解决思路: 通过父子组件通讯($refs 和 props) props接受参数, $refs调用子组件的方法 来达到点击提交改变按钮状态,如果不成功则取消按钮状态 在src/components/ 下建一个button.vue <template> <!-- use plane --> <!-- 传入bgColor改变按钮背景色 --> <!-- state切换button的

  • 利用vue开发一个所谓的数独方法实例

    1.前言 最近工作中遇到一个问题,因为后台管理系统页面功能暂时没有新的需求,就在想首页放什么东西,最近我想到的就是放个所谓的数独,为什么是所谓的数独,因为规则不同于标准的数独,只要求每一行每一列数字不一样就可以了!这个实例也是基于vue的,代码分享给大家.给大家代码,并不是要让大家直接拷贝代码,而是希望能让大家当做是一个练手的项目,或者学习到知识.如果大家觉得我哪里写得不好,写错了,欢迎指出,让大家交流意见,一起进步. 代码上传到github了:有需要的可以star一下!vue-demos 2.

  • vue实现一个炫酷的日历组件

    公司业务新开了一个商家管理微信H5移动端项目,日历控件是商家管理员查看通过日程来筛选获取某日用户的订单等数据. 如图: 假设今天为2018-09-02 90天前: 90天后; 产品需求: 展示当前日期(服务器时间)前后90天,一共181天的日期. 日历可以左右滑动切换月份. 当月份的如果不在181天区间的,需要置灰并且不可点击. 点击日历绑定的节点的外部,关闭弹窗. 涉及内容: 获取服务器时间,渲染日历数据 vue-touch监听手势滑动事件 ios日期兼容处理 clickOutSide自定义指

  • MySQL的慢日志线上问题及优化方案

    MySQL 慢日志(slow log)是 MySQL DBA 及其他开发.运维人员需经常关注的一类信息.使用慢日志可找出执行时间较长或未走索引等 SQL 语句,为进行系统调优提供依据. 本文将结合一个线上案例,分析如何正确设置 MySQL 慢日志参数和使用慢日志功能,并介绍下网易云 RDS 对 MySQL 慢日志功能的增强. MySQL 参数组功能 网易云 RDS 实例提供了参数组管理功能,可通过参数管理界面查看绝大部分常用的 MySQL 系统参数,用户可了解当前运行值和建议值: 用户还可通过参

随机推荐