用户登录校验成功后:

signKeysignKeyhashDatardsKeyhashDatasignKeyrdsKey

登录后用户其他操作:

前端需要将保存的token传给后端。

rdsKeysignKeyrdsKeyrdsKeysignKeyhashDatasignKeyhashData
rdsKey

后期拓展:

  • 后期可在redis中存储权限map,校验登录完成后,可立即开始校验用户权限。
具体代码:

后端使用的是 beego api ,作为一个Restful风格的服务端,还支持自动生成swagger风格文档。

先增加登录成功后的代码

在controller的用户登录函数中:

	// todo:
	// 1、前置的操作,比如用户信息从数据库查询,比对密码之类的,太多例子,这里就不写了。
	// 2、总之,用户登录信息验证通过后,开始执行如下:
	
	// 创建一条aes加密数据
	signKey := sid.New() //随机生成即可,可以使用rand之类的生成一个符合AES CBC模式加密的密钥就行
	ok, hashData := utils.AesEncryptCBC([]byte(user.Id), []byte(signKey))
	// utils.AesEncryptCBC() 方法就是执行加密操作。
	// 之前文章有所介绍:https://blog.csdn.net/mirage003/article/details/87868999
	if !ok {
		return reData.msg(ErrServerError)
		// 这里是返回给前端一条类似于内部错误的消息,说明加密的时候出错,不能进行下一步。
	}
	
	// 在redis中存储一条数据,并设定过期时间(到期之间内未操作,自动删除)
	rdsVal := make(map[string]interface{}, 3)
	rdsVal["user"] = user         //用户信息,将数据库中的用户信息保存到redis中;
	rdsVal["hashData"] = base64.StdEncoding.EncodeToString(hashData) //aes加密数据 hashData;
	//rdsVal["prodId"] =  prod.Id //当前产品的id
	ok, rdsKey := rds.PutJSON("", "user", rdsVal, 1800*time.Second) 
	// redis存储,并设定1800秒后数据到期
	// beego中如何使用redis可以参考:https://beego.me/docs/module/cache.md
	if !ok {
		return reData.msg(ErrServerError)
		// 这里是返回给前端一条类似于内部错误的消息,说明redis存储失败,不能进行下一步。
	}

	// 创建一条token数据
	tokenData := make(map[string]interface{}, 3)
	tokenData["id"] = user.Id
	tokenData["signKey"] = signKey
	tokenData["rdsKey"] = rdsKey
	ok, tokenStr := utils.GetHStoken(&tokenData, conf.SecretKey) 
	// 生成HS256算法的token
	// 网上太多例子,这里不再写了。
	if !ok {
		return reData.msg(ErrServerError)
		// 这里是返回给前端一条类似于内部错误的消息,说明token生成失败,不能进行下一步。
	}

	// 最后,将token传给前端
	data := make(map[string]string, 1)
	data["token"] = tokenStr
	return reData.msg(OK).res(true).data(data)

然后增加一个路由过滤器 filter

beego中很方便就能添加,参考文档:https://beego.me/docs/mvc/controller/filter.md

接着在filter中实现验证和读取:

func filter() {
	var FilterBase = func(ctx *context.Context) {
		urlPath := ctx.Request.URL.Path
		if urlPath == "/v1/user/login" { //登录页面不检查
			return
		}
		
		// 获取token
		var token string
		if token = ctx.Request.Header.Get("YS-Token"); token == "" { //先从header里面取出token
			// 如果没取到,说明用户未登录
			result(ctx,"50008","请登录") // 返回消息通知前端让用户进行登录
			return
		}
		
		// 解析 token
		ok, data := utils.ParseHStoken(token, conf.SecretKey)
		if !ok { //如果token解析失败
			result(ctx,"50008","令牌验证失败,请重新登录。") // 返回消息通知前端让用户进行登录
			return
		}
		rdsKey := jsoni.GetStr(*data, "rdsKey")   // 从token中获取 rdsKey
		signKey := jsoni.GetStr(*data, "signKey") // 从token中获取 signKey
		tUID := jsoni.GetStr(*data, "id")         // 从token中获取 用户id
		// jsoni是我自己封装的一个函数,
		// 调用的是  github.com/json-iterator/go 这个第三方库,
		// 运行效率比自带的快很多(据说golang 1.10+版本以上,两者差距不大了。所以请自行斟酌。)
		
		// 开始对用户进行登录验证
		code, rdsData := rds.GetBytes(rdsKey)     //查询redis
		if code == 0 { // redis查询返回0,代表出错(我自己定义的一个方法)
			result(ctx,"50008","服务器发生错误,请重试。")
			return
		}else if code==1{ // redis查询返回1,代表未找到(我自己定义的一个方法)
			result(ctx,"50008","登录超时,请重新登录。")
			return
		}
		hashData := jsoni.GetStr(*rdsData, "hashData")          // 从rdsData中获取 hashData
		bytes, err := base64.StdEncoding.DecodeString(hashData) // hashData转为[]byte
		if err != nil {
			beego.Error("routers.filter.FilterBase: ", err)
			result(ctx,"50008","服务器发生错误,请重试。")
			return
		}
		// 验证aes加密
		if ok, decrypted := utils.AesDecryptCBC(bytes, []byte(signKey)); !ok {
			result(ctx,"50008","服务器发生错误,请重试。")
			return
		} else {
			if string(decrypted) != tUID {
				result(ctx,"50008","验证失败")
				return
			}
		}
		
		// 执行到这里,说明用户登录验证已经完成,开始将用户信息提取出来
		// 这里我将用户信息加到header中,在controller函数内就可以直接取到,不用再次查询redis了
		userData := jsoni.GetStr(*rdsData, "user")
		if userData == "" { //如果没有获取到用户信息,这里只是一个容错处理,redis中获取用户信息失败的概率很小
			// 将用户的id传过去
			ctx.Request.Header.Add("userData", `{id:"`+tUID+`"}`)
		} else { //否则,直接传入用户的全部信息
			ctx.Request.Header.Add("userData", userData)
		}
	}
	beego.InsertFilter("/*", beego.BeforeRouter, FilterBase)	
}

最后,在controller用户登出控制函数中,增加一个删除redis数据的方法即可。(当然,不删除也行,该数据到期以后,redis会自动清除)

运行效果:

1、登录:
在这里插入图片描述
2、登陆后的其他操作验证:
在这里插入图片描述
校验成功,正常进入controller对应的函数内 ↑

在这里插入图片描述
未传入token,提示请登录 ↑

在这里插入图片描述
token数据被修改,提示重新登录↑