本文将带你了解如何使用Golang实现Jwt登录验证即实现一个jwt的token签发以及中间件验证方法。
关于jwt有关的知识点可以参考阮一峰的博客,此处不再赘述。
如果想使用jwt解析器可以到Jwt官方网站。
如果你想学习Go以及上线一个简单的网盘项目,欢迎学习或者参与进我的开源项目Go-Cloud-Disk。如果能给我的项目点一个star更好不过,你的鼓励与点赞会使得我的项目和博客变得更好!
使用到的Go包
Gin:本文将使用Gin进行路由注册。官方教程
Go-jwt: golang使用jwt的包。官方教程
go get -u github.com/golang-jwt/jwt/v5
go get -u github.com/gin-gonic/gin
package main
import (
"errors"
"time"
"github.com/golang-jwt/jwt/v5"
)
// 填写你的jwt密钥
var jwtKey = "23333333333"
// jwt中存储的信息
type MyClaims struct {
// 你想要往jwt中存储的信息,这里简单存储用户id,名称
UserId string `json:"user_id"`
UserName string `json:"user_name"`
jwt.RegisteredClaims // 一定要包含该Client
}
// User 用户信息示例
type User struct {
UserId string
UserName string
}
// GenToken 根据传入的用户信息生成一个jwt密钥
// issuer 一般填写签发人员
// expireHour 填写有效时间,小时制
func GenToken(issuer string, expireHour int, user User) (string, error) {
mySigningKey := []byte(jwtKey)
claims := MyClaims{
UserId: user.UserId,
UserName: user.UserName,
RegisteredClaims: jwt.RegisteredClaims{
Issuer: issuer, // 填入签发者
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(expireHour) * time.Hour)), // 填写到期时间
IssuedAt: jwt.NewNumericDate(time.Now()), // 填写签发时间
},
}
// 根据选择的加密方式生成jwt密钥
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(mySigningKey)
}
调用对应函数
package main
import "fmt"
func main() {
userInfo := User{
UserId: "66666",
UserName: "miaoqiu",
}
token, err := GenToken("miaoqiu", 24, userInfo)
if err != nil {
return
}
fmt.Println(token)
}
输出
PS C:\Users\Admin\Desktop\Go\go-jwt-learn> go build
PS C:\Users\Admin\Desktop\Go\go-jwt-learn> .\learn.exe
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiNjY2NjYiLCJ1c2VyX25hbWUiOiJtaWFvcWl1IiwiaXNzIjoibWlhb3FpdSIsImV4cCI6MTcyMDAxMjI3OSwiaWF0IjoxNzE5OTI1ODc5fQ.Dz7WJY-jvo1P-epsz6EQcR1p1mrv6AH-4tUXVYy7k4U
到官网解析一下token
成功签发!!!
注意,可以从官网解析中发现,jwt为默认明文传输,请不要存放敏感信息,如果要存放敏感信息可以用密钥再加密一次。
golang解析token函数,
func ParseToken(tokenString string) (*MyClaims, error) {
mySigningKey := []byte(jwtKey) //填入自己存放的jwt密钥
token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(t *jwt.Token) (interface{}, error) {
return mySigningKey, nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*MyClaims); ok && token.Valid {
return claims, nil
}
return nil, errors.New("tokenErr")
}
package main
import (
"strings"
"time"
"github.com/gin-gonic/gin"
)
func JWTAuth() gin.HandlerFunc {
return func(c *gin.Context) {
// 存放token一般都是在请求头部的Authorization按该格式存放"Bearer [token]"
authorization := c.Request.Header.Get("Authorization")
if authorization == "" {
c.JSON(200, "NeedToken")
c.Abort()
return
}
// 由于"Bearer [token]"中间存在空格直接切分即可
parts := strings.Split(authorization, " ")
// 判断格式是否正确
if len(parts) != 2 || parts[0] != "Bearer" {
c.JSON(200, "TokenFormatErr")
c.Abort()
return
}
// 解析token
claims, err := ParseToken(parts[1])
if err != nil {
c.JSON(200, "TokenErr")
c.Abort()
return
}
// 判断是否过期
if time.Now().Unix() > claims.ExpiresAt.Unix() {
c.JSON(200, "TokenExpiration")
c.Abort()
return
}
// 向context中存放信息
c.Set("UserId", claims.UserId)
c.Set("UserName", claims.UserName)
// 获取信息可以使用
// userId := c.MustGet("UserId").(string)
c.Next()
}
}
// Login check username and password can matched
// and return user info and jwt token
func (service *UserLoginService) Login(c *gin.Context) serializer.Response {
// 校验具体账号密码是否正确.......
// 签发token
token, err := utils.GenToken("miaoqiu", 24, &user)
if err != nil {
return serializer.InternalErr("GetTokenErr", err)
}
// 格式化返回token和登录用户信息
return serializer.Success(returnUser{
Token: token,
User: serializer.BuildUser(user),
})
}
v1 := r.Group("/api/v1")
{
// 不需要判断的接口放在外部
v1.POST("user/login", api.UserLogin)
v1.POST("user/register", api.UserRegiser)
auth := v1.Group("")
auth.Use(JWTAuth())
{
// 放入需要token 判断的接口
}
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。