一、JWT介绍 1、什么是JWT
2、jwt三部分
二、JWT基本用法 1、定义需求
// MyClaims自定义声明结构体内嵌jwt.StrandardClaims //jwt包自带的jwt.StandardClaims只包含额官方字段 //我们这里需要额外记录一个username字段。所以要自定义结构体 //如果想要保存更多信息,都可以添加奥这个结构体中 type MyClaims struct { Username string `json:'username'` jwt.StandardClaims }
var MySecret = []byte('下古今之庸人皆以一惰字致败天下古今之才人皆以一傲字致败') 2、生成JWT
3、解析JWT // ParseToken 解析JWT func ParseToken(tokenString string) (*MyClaims, error) { // 解析token token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (i interface{}, err error) { return MySecret, nil }) if err != nil { return nil, err } if claims, ok := token.Claims.(*MyClaims); ok && token.Valid { // 校验token return claims, nil } return nil, errors.New('invalid token') } 三、gin使用JWT 1、demo结构 2、main.go
3、controllers/user.go package controllers
import ( 'github.com/gin-gonic/gin' 'jwt-test/pkg/jwt' 'net/http' )
// ParamSignUp 注册请求参数 type UserInfo struct { Username string `json:'username' binding:'required'` Password string `json:'password' binding:'required'` RePassword string `json:'confirm_password' binding:'required,eqfield=Password'` //RePassword string `json:'re_password' binding:'required,eqfield=Password'` }
func AuthHandler(c *gin.Context) { // 用户发送用户名和密码过来 var user UserInfo err := c.ShouldBind(&user) if err != nil { c.JSON(http.StatusOK, gin.H{ 'code': 2001, 'msg': '无效的参数', }) return } // 校验用户名和密码是否正确 if user.Username == 'zhangsan' && user.Password == '123456' { // 生成Token tokenString, _ := jwt.GenToken(user.Username) c.JSON(http.StatusOK, gin.H{ 'code': 2000, 'msg': 'success', 'data': gin.H{'token': tokenString}, }) return } c.JSON(http.StatusOK, gin.H{ 'code': 2002, 'msg': '鉴权失败', }) return }
func HomeHandler(c *gin.Context) { username := c.MustGet('username').(string) c.JSON(http.StatusOK, gin.H{ 'code': 2000, 'msg': 'success', 'data': gin.H{'username': username}, }) } 4、pkg/jwt/jwt.go
5、middlewares/auth.go package middlewares
import ( 'github.com/gin-gonic/gin' 'jwt-test/pkg/jwt' 'net/http' 'strings' )
// JWTAuthMiddleware 基于JWT的认证中间件 func JWTAuthMiddleware() func(c *gin.Context) { return func(c *gin.Context) { // 客户端携带Token有三种方式 1.放在请求头 2.放在请求体 3.放在URI // 这里假设Token放在Header的Authorization中,并使用Bearer开头 // 这里的具体实现方式要依据你的实际业务情况决定 authHeader := c.Request.Header.Get('Authorization') if authHeader == '' { c.JSON(http.StatusOK, gin.H{ 'code': 2003, 'msg': '请求头中auth为空', }) c.Abort() return } // 按空格分割 parts := strings.SplitN(authHeader, ' ', 2) if !(len(parts) == 2 && parts[0] == 'Bearer') { c.JSON(http.StatusOK, gin.H{ 'code': 2004, 'msg': '请求头中auth格式有误', }) c.Abort() return } // parts[1]是获取到的tokenString,我们使用之前定义好的解析JWT的函数来解析它 mc, err := jwt.ParseToken(parts[1]) if err != nil { c.JSON(http.StatusOK, gin.H{ 'code': 2005, 'msg': '无效的Token', }) c.Abort() return } // 将当前请求的username信息保存到请求的上下文c上 c.Set('username', mc.Username) c.Next() // 后续的处理函数可以用过c.Get('username')来获取当前请求的用户信息 } } 四、测试 1、登录获取token
2、携带token访问
Authorization Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InpoYW5nc2FuIiwiZXhwIjoxNjIzNjY3NzUzLCJpc3MiOiJteS1wcm9qZWN0In0.j9SFygMnMq1-ymsDcTLN59svQb4-BTgO3DLaBeUAAVY |
|