技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-9.登...

共 4527字,需浏览 10分钟

 ·

2021-08-25 14:39

技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-9.登录功能(三):登录的token验证

相关文章:
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-1.工具和本地环境

技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-8.模型的关联——无限层级分类
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-9.登录功能(一):管理员功能的实现
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-9.登录功能(二):用户登录和密码验证
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-9.登录功能(三):登录的token验证
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-10.生产环境编译

1.生成token

go语言中生成token的方法被封装在了jwt中,gin框架使用jwt又进行了进一步封装,在"github.com/dgrijalva/jwt-go"里。
(1)安装jwt包:jwt-go

go get github.com/dgrijalva/jwt-go

3d9cae102317a928e3049bf12d3eb15c.webp
(2)编写生成token方法

// 定义一个全局token密钥,token密钥随意定义一串字符串
var jwtkey = []byte("lskjdghfhkagflkagh")
// 定义字符串格式token,方便之后token的转化
var tokenString string

// 定义一个token模型,用于存放token信息,识别不同账号
type claims struct {
UserId string
jwt.StandardClaims
}

// 生成token
// 传入字符串格式用户id,输出字符串格式的token和错误值
func setToken(id string) (tokenString string, err error) {
//
// 定义token过期时间,一天后过期
expireTime := time.Now().Add(1 * 24 * time.Hour)
claims := &claims{
UserId: id,
StandardClaims: jwt.StandardClaims{
ExpiresAt: expireTime.Unix(), // 过期时间,用上方定义的过期时间
IssuedAt: time.Now().Unix(), // 生效时间,生成token的这一刻起
Issuer: "127.0.0.1", // 生成者,本域名
Subject: "user token", // 生成主题
},
}
// 生成token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// 根据之前定义的密钥,将token转化为加密字符串
tokenString, err = token.SignedString(jwtkey)
// 输出
return
}

5fefa95f37c7ab54135a1578dc4af0af.webp
(2)编辑登录接口方法,在其中使用token方法获取token值
75b1d24c54f4f7e9dbc30c42572dccca.webp
编译启动,测试:
b3a6a8f7ff5a731beaa743f2b5ea4e77.webp
成功获取token值。
(3)最后将token值保存到前端本地储存空间中,用于验证登录状态:
Login.vue:

async login() {
const res = await this.$http.post('login', this.model)
console.log(res)

// 存储token值
// sessionStorage是页面缓存存储,关闭页面后token值被清除,每次进入页面都需要进行账号登陆
// localStorage是本地存储,关闭页面后token值不会被清除,只要不清理浏览器缓存就无需再次进行登录操作
localStorage.token = res.data.token

// 登录成功跳转到网站首页
this.$router.push('/')
// 使用vue效果在页面展示结果
this.$message({
type: 'success',
message: '登陆成功'
})
}

b64be2620214ca2bf0a18b0624118685.webp
保存测试,跳转成功:
42222fed8b1578b7e2792323987c377f.webp
查找页面存储的token,可查询到:
a5e3940a1f2aea7fd2f939758fb8ffbc.webp

2.验证token

我们需要将token值存入发送请求的请求头中,做到只要调用接口,就可以将token一并发送到后端,从而对token登陆状态进行比对验证。
(1)前端admin端通过请求头将token传值给后端
在http.js中全局设置获取token,将token值传入请求头Request
Headers中,然后后台接口中直接从请求头中获取token,从而实现验证。
这里使用axios里的Interceptors方法,详细可查阅axios手册:
bff1a25627075a156671d49cbb07ec7b.webp
admin/http.js前端admin端将token传入请求头Request Header:

// 使用axios的interceptors拦截器,将http调用时拦截
http.interceptors.request.use(function(config){
// 将token值传入请求头,"bearer + 空格"是代码规范,看到Bearer(持票人)大家就明白是对token的验证
config.headers.Authorization = 'bearer ' + localStorage.token
return config
}, function(error){
// 错误处理
return Promise.reject(error)
})

a738136a862ab1a8f86c80186dfbd505.webp
此时调用接口就可以将本地token传给请求头,测试:
fe2216ea8a7a347bf3b80b11a3a773b5.webp
(2)后端获取请求头中的token值,并解析token

// 解析token
func getToken() gin.HandlerFunc {
return func(ctx *gin.Context) {
// 从请求头获取token值
tokenString := ctx.GetHeader("Authorization")

// 判断如果没有token
if tokenString == "" {
ctx.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "您未登录"})
// 中间件中使用next()就执行下一步,如果执行abort()就不会执行下一步
ctx.Abort()
// return
}

// 去除authorization中的"bearer"
tokenString = strings.Trim(tokenString, "bearer")
// 去除authorization中的空格
tokenString = strings.Replace(tokenString, " ", "", -1)
fmt.Println(tokenString)

// 判断token是否失效
token, claims, err := ParseToken(tokenString)
if err != nil || !token.Valid{
ctx.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "权限失效,请重新登录"})
ctx.Abort()
// return
}

// 打印userid,既然定义这个值就必须使用,留下来以备以后的需要
fmt.Println(claims.UserId)
if claims.UserId != "" {
// 如果没有token没问题,则退出中间件执行下一步
ctx.Next()
}
}

}
// 解析字符串token中的信息
func ParseToken(tokenString string) (*jwt.Token, *claims, error) {
claims := &claims{}
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (i interface{}, err error) {
return jwtkey, nil
})
return token, claims, err
}

818679ed8e6d505e9c47e06590fc6253.webp
此时,删除本地token:
404760e58ff89e5f2b9c3dff498fa04a.webp
刷新页面,进行token判断:
481619409ff19b214ce486026a56ccb1.webp
此时接口无法调用,这里是因为我们删除了本地存储的token,如果本地有token,但仍然错误,就是因为之前token设定的时间过期了:
26f426d26d63016b3de69e4cdc01d2bf.webp
同时报错中显示为空白,我们需要让它显示出来报错原因,修改两处:
(1)将报错返回的json值return返回:
6ae356b6dc046004339335eee3dfc99e.webp
(2)修改前端页面的vue拦截信息,我们返回的错误是msg:
a180a5c00f4492565f56bf68513d7905.webp
此时再次刷新页面:
d1a9cf762edaee677f16c16b1ea68b8a.webp
既然报错,则跳转到登陆页面:
6d1ce7994350737bed3549bada9c40e5.webp
刷新页面,此时跳转到登录页面:
8e57cfe93bcde594da231230c8029b8a.webp
登录进入页面测试,无法登录:
66c215c7b65b31e13f72791d7e49d274.webp
这事因为我们的token判断中间件,同样作用于login接口,所以需要进行改动后端接口路由:
6ed4ddd048b8d14b50e97560a7223446.webp
将登录接口放在token解析中间件上方,中间件就不会对登录接口作用了,只会作用于下方接口,保存编译测试:
91b4538c5ae4bfa352ece2e68760d950.webp
到此,登录的token解析功能实现。

3.解析token总结

只要我们确立好实现token验证的过程方向后就可以完成这个功能。登录的token验证过程非常简单,就是调用接口→发送token→接收token→判断token→将token判断结果传给前端→如已登录运行接口(若未登录跳转登录页)→返回数据,我们的搭建过程就是对每个步骤进行逐一寻找找方法、解决。

4.导航守卫

此时我们只要调用接口就会解析token,但是进入没有接口的页面就不会跳转。如果我们不想让用户在不登陆的状态下访问我们的所有网页,就需要在前端也设置token判断,做到只要不登录,就无法访问所有页面。
这里我们就需要用到Vue的导航守卫
大家可以查看我之前的文章进行设置,纯前端操作,不涉及后端:

技能学习:学习使用Node.js + Vue.js,开发前端全栈网站-12-4.登陆的前端vue-router路由验证(导航守卫)

到此就完成了一个简单的全栈项目,大家可以参照学习过程研究更多功能,下篇文章将admin端放入server端,通过server端进行项目的访问,将前后端分离状态合并成一个完整的独立项目(改为待上线模式,还是前后端分离)。

更多设计、功能的学习经验,大家也可以去我的公众号查看!

————


浏览 34
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报