1、token主要有两个作用:
(1)防止表单重复提交(设置在多少时间内)
原理:在服务器端生成一个唯一的随机标识号,专业术语称为Token(令牌),同时在当前用户的Session域中保存这个Token。
然后将Token发送到客户端的Form表单中,在Form表单中使用隐藏域来存储这个Token,表单提交的时候连同这个Token一起提交到服务器端,
然后在服务器端判断客户端提交上来的Token与服务器端生成的Token是否一致,如果不一致,那就是重复提交了,
此时服务器端就可以不处理重复提交的表单。如果相同则处理表单提交,处理完后清除当前用户的Session域中存储的标识号
https://blog.csdn.net/qq_38714573/article/details/78771862
(2)用来作身份验证(登陆获得token后判断请求带的token是否相同)
原理:使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:
客户端使用用户名跟密码请求登录
服务端收到请求,去验证用户名与密码
验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据
https://blog.csdn.net/qq_32784541/article/details/79655146
2、token验证流程
1,注册用户信息,前端将用户名及密码发给后端
2,后端接收参数并存入数据库,再生成token返回给前端(token主要是用来验证用户的登录状态)
3,前端接收到后端返回的token,就把它存在sessionStorage里面
4,前端实现登录,将用户名跟密码传送给后台,并带上token。
5,后端返回一个新的token给前端,并且验证用户名和密码是否正确,将结果返回给前端。
6,前端接收到后端返回的消息,执行相应的操作,同时把token存到sessionStorage里面。
7,登录成功之后,跳转到首页,并且请求首页的数据回来,带上token传给后端。
8,后端接收到前端传来的token,判断是否有效。若有效,就返回相应的数据信息给前端;若无效,则返回“登录失败,重新登录类似的字段”。
9,前端接收到后端返回的消息,并执行相应的操作。
https://blog.csdn.net/weixin_43748930/article/details/87901038
3、代码解析
//token里面添加用户信息,验证token后可能会用到用户信息
type MyClaims struct {
UserName string `json:"user_name"`
UserId string `json:"user_id"`
jwt.StandardClaims
}
// 根据用户名生成token,传递给客户端
func GenToken(username string, userId string) (token string) {
myClaims := MyClaims{
username,
userId,
jwt.StandardClaims{
NotBefore: int64(time.Now().Unix()),
ExpiresAt: int64(time.Now().Unix() + 86400), // 86400 为一天
Issuer: "duxiaoman",
},
}
key := beego.AppConfig.String("TokenSignKey")
fmt.Println(key)
ss := jwt.NewWithClaims(jwt.SigningMethodHS256, myClaims)
token, _ = ss.SignedString([]byte(key))
return token
}
//beego.AppConfig.String()读取配置信息
读取不同模式下配置参数的方法是“模式::配置参数名”,比如:beego.AppConfig.String(“dev::mysqluser”)。
https://blog.csdn.net/qq_33610643/article/details/53511058
// 解析token,判断token 是否有效 有效的话提取用户信息
func ValidateTokenMiddleware(tokenString string) (username string, userId string, isOk bool) {
olog.Debug("start validate token")
token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(beego.AppConfig.String("TokenSignKey")), nil
})
claims, ok := token.Claims.(*MyClaims)
if ok && token.Valid {
username = claims.UserName
userId = claims.UserId
isOk = ok
olog.Debug("token is validate")
} else {
olog.Debug("token is not validate ,err is ", err)
}
return
}
// 登陆后其他操作,认证请求用户是否有token
var AuthFilter = func(ctx *context.Context) {
if ctx.Request.RequestURI != "/fsg-resource/ui/auth/login" {
olog.Debug("start auth request")
token := ctx.Request.Header.Get("Authorization")
if token != "" {
username, userId, isOk := ValidateTokenMiddleware(token)
olog.Debug("request is ok ,username is ", username)
if isOk {
ctx.Input.SetData("username", username)
ctx.Input.SetData("userID", userId)
}
if !isOk {
olog.Debug("request token is not validate")
ctx.Redirect(401, "/401")
}
} else {
olog.Debug("request token is not exists")
ctx.Redirect(401, "/401")
}
}
}
URI,是uniform resource identifier,统一资源标识符,用来唯一的标识一个资源。
而URL是uniform resource locator,统一资源定位器,它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。
https://www.jianshu.com/p/449b30411964
获取token:token := ctx.Request.Header.Get(“Authorization”)
在HTTP请求中token通常放在Authorization字段中
根据token获取用户信息:username, userId, isOk := ValidateTokenMiddleware(token)
https://hacpai.com/article/1540349739379
ctx.Input.SetData(“username”, username)
GetData用于从控制器中的过滤器获取数据。它允许您传递不仅仅是字符串的值。
从Beego文档中:GetData获取输入中数据的值
SetData输入中数据的设置值。GetData和SetData用于将数据从过滤器传递到控制器
https://stackoverflow.com/questions/50373654/functionality-of-beego-syntax-ctx-input-getdatavariable-name
完整的token代码
https://www.cnblogs.com/dust90/p/11168585.html
https://www.cnblogs.com/zhzhlong/articles/10009141.html
https://studygolang.com/articles/24285?fr=sidebar
// 认证ticket,正确返回token
func AuthTicket(ticket string, nexturl string) (userInfo map[string]interface{}, err error) {
olog.Debug("认证ticket")
url := fmt.Sprintf("%s?service=%s?next=%s&ticket=%s&appKey=%s", global.UUAPAuthUrl, global.ServiceUrl, nexturl, ticket, global.UUAPAppKey)
olog.Debug(url)
resp, err := http.Get(url)
if err == nil {
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
username, err := parserXml(string(body))
if err == nil {
// 获取到username 生成token
userInfo = UserAuth(username)
token := GenToken(username, strconv.Itoa(userInfo["userID"].(int)))
userInfo["token"] = token
olog.Debug("认证ticket 成功", ticket)
}
}
return
}
ctx.Input.SetData()与c.Ctx.Input.GetData()的原理
ctx.Input.SetData()一对一的关系
用户认证之后会有token,每次请求都会拿着这个token来,token解析之后里面是用户的信息。
每次请求都会先去验证token,验证成功会setData 用户名,然后 在controller里才能get到值 。