技能学习:学习使用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
(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
}
(2)编辑登录接口方法,在其中使用token方法获取token值
编译启动,测试:
成功获取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: '登陆成功'
})
}
保存测试,跳转成功:
查找页面存储的token,可查询到:
2.验证token
我们需要将token值存入发送请求的请求头中,做到只要调用接口,就可以将token一并发送到后端,从而对token登陆状态进行比对验证。
(1)前端admin端通过请求头将token传值给后端
在http.js中全局设置获取token,将token值传入请求头Request
Headers中,然后后台接口中直接从请求头中获取token,从而实现验证。
这里使用axios里的Interceptors方法,详细可查阅axios手册:
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)
})
此时调用接口就可以将本地token传给请求头,测试:
(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
}
此时,删除本地token:
刷新页面,进行token判断:
此时接口无法调用,这里是因为我们删除了本地存储的token,如果本地有token,但仍然错误,就是因为之前token设定的时间过期了:
同时报错中显示为空白,我们需要让它显示出来报错原因,修改两处:
(1)将报错返回的json值return返回:
(2)修改前端页面的vue拦截信息,我们返回的错误是msg:
此时再次刷新页面:
既然报错,则跳转到登陆页面:
刷新页面,此时跳转到登录页面:
登录进入页面测试,无法登录:
这事因为我们的token判断中间件,同样作用于login接口,所以需要进行改动后端接口路由:
将登录接口放在token解析中间件上方,中间件就不会对登录接口作用了,只会作用于下方接口,保存编译测试:
到此,登录的token解析功能实现。
3.解析token总结
只要我们确立好实现token验证的过程方向后就可以完成这个功能。登录的token验证过程非常简单,就是调用接口→发送token→接收token→判断token→将token判断结果传给前端→如已登录运行接口(若未登录跳转登录页)→返回数据,我们的搭建过程就是对每个步骤进行逐一寻找找方法、解决。
4.导航守卫
此时我们只要调用接口就会解析token,但是进入没有接口的页面就不会跳转。如果我们不想让用户在不登陆的状态下访问我们的所有网页,就需要在前端也设置token判断,做到只要不登录,就无法访问所有页面。
这里我们就需要用到Vue的导航守卫。
大家可以查看我之前的文章进行设置,纯前端操作,不涉及后端:
技能学习:学习使用Node.js + Vue.js,开发前端全栈网站-12-4.登陆的前端vue-router路由验证(导航守卫)
到此就完成了一个简单的全栈项目,大家可以参照学习过程研究更多功能,下篇文章将admin端放入server端,通过server端进行项目的访问,将前后端分离状态合并成一个完整的独立项目(改为待上线模式,还是前后端分离)。
更多设计、功能的学习经验,大家也可以去我的公众号查看!
————