IM即时通讯-用户注册登录,及gin+JWT鉴权(三)

用户信息表

// User model
type User struct {
	Id       string `json:"id" form:"id" bson:"_id"`                      // 用户id,直接用mongo的_id
	Username string `json:"username" form:"username" bson:"username"`     // 登录账号
	Password string `json:"password" form:"password" bson:"password"`     // 密码
	Nickname string `json:"nickname" form:"nickname" bson:"nickname"`     // 昵称
	Avator   string `json:"avator,omitempty" form:"avator" bson:"avator"` // 个性化头像
	Sign     string `json:"sign,omitempty" form:"sign" bson:"sign"`       // 签名
}

注册

// Register 注册
func Register(register *RegisterForm) (*mongo.InsertOneResult, error) {
	filter := bson.M{
		"username": register.Username,
	}
	result := app.MongoDBClient.Database(app.MongoDataBaseName).Collection("user").FindOne(context.TODO(), filter)
	if err := result.Err(); err != nil {
		if err == mongo.ErrNoDocuments {
			return app.MongoDBClient.Database(app.MongoDataBaseName).Collection("user").InsertOne(context.TODO(), register)
		}
		return nil, err
	}

	return nil, errors.New("username exist")

}

登录

type LoginForm struct {
	Username string `json:"username" form:"username" bson:"username"`
	Password string `json:"password" form:"password" bson:"password"`
}
// Login 验证登录信息
func Login(filter LoginForm) (User, error) {
	var user User
	err := app.MongoDBClient.Database(app.MongoDataBaseName).Collection("user").FindOne(context.TODO(), filter).Decode(&user)
	if err != nil {
		return user, err
	}
	return user, nil
}

注册、登录那都常规操作咯,下面来实现 gin+jwt 的鉴权

登录信息验证通过后,会生成一个token返回给客户端,之后的访问资源需要携带token

jwt中间件 util/jwt/jwt.go

package jwt

import (
	"errors"
	"net/http"

	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
)

var (
	ErrorTokenExpired     error  = errors.New("token is expired")
	ErrorTokenNotValidYet error  = errors.New("token not active yet")
	ErrorTokenMalformed   error  = errors.New("that's not even a token")
	ErrorTokenInvalid     error  = errors.New("couldn't handle this token")
	SignKey               string = "MySignKey"
)

// Auth middleware, check the token
func Auth() gin.HandlerFunc {
	return func(context *gin.Context) {
		// Get the token in the request context
		token := context.Request.Header.Get("token")
		if token == "" {
			context.JSON(http.StatusOK, gin.H{
				"code": 10000,
				"msg":  "No token, illegal access",
			})
			context.Abort()
			return
		}

		jwt := NewJWT()
		// parseToken 解析token包含的信息
		claims, err := jwt.ParseToken(token)
		if err != nil {
			context.JSON(http.StatusOK, gin.H{
				"code": 10001,
				"msg":  err.Error(),
			})
			context.Abort()
			return
		}
		// Proceed to the next route and pass on the parsed information
		context.Set("claims", claims)
	}
}

// JWT signature structure
type JWT struct {
	SigningKey []byte
}

// Create a new JWT instance
func NewJWT() *JWT {
	return &JWT{
		SigningKey: []byte(GetSignKey()),
	}
}

// Access to signKey
func GetSignKey() string {
	return SignKey
}

//
func SetSignKey(key string) string {
	SignKey = key
	return SignKey
}

// Payloads, you can add the information you need
type CustomClaims struct {
	Name string `json:"name"`
	jwt.StandardClaims
}

// CreateToken generates a token
func (j *JWT) CreateToken(claims CustomClaims) (string, error) {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(j.SigningKey)
}

// ParseToken
func (j *JWT) ParseToken(tokenString string) (*CustomClaims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		return j.SigningKey, nil
	})
	// There is a problem with token resolution
	if err != nil {
		if ve, ok := err.(*jwt.ValidationError); ok {
			if ve.Errors&jwt.ValidationErrorMalformed != 0 {
				return nil, ErrorTokenMalformed
			} else if ve.Errors&jwt.ValidationErrorExpired != 0 {
				// Token is expired
				return nil, ErrorTokenExpired
			} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
				return nil, ErrorTokenNotValidYet
			} else {
				return nil, ErrorTokenInvalid
			}
		}
	}
	if token != nil {
		if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
			return claims, nil
		}
	}
	return nil, ErrorTokenInvalid
}

生成token

import (
	"fmt"
	"im-demo/application/model"
	"net/http"
	"time"

	myjwt "im-demo/util/jwt"

	jwtgo "github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
)

func newToken(user model.LoginForm) (string, error) {
	jwt := myjwt.NewJWT()
	claims := myjwt.CustomClaims{
		Name: user.Username,
		StandardClaims: jwtgo.StandardClaims{
			NotBefore: int64(time.Now().Unix() - 1000),  // Effective time of signature
			ExpiresAt: int64(time.Now().Unix() + 36000), // Expiration time is one hour
			Issuer:    "footmark",                       // Signed issuer
		},
	}
	token, err := jwt.CreateToken(claims)
	return token, err
}

携带token请求用户信息

gin路由,以及使用jwt中间件

// 分组路由
infoGroup := engine.Group("/info")
infoGroup.Use(jwt.Auth())
{
	infoGroup.GET("/userinfo", api.GetUserInfo)

}

ajax请求,在请求头header中携带token

$.ajax({
    url: "/info/userinfo",
    type: "GET",
    headers: {
        "token": token
    },
    data: {
        "owner_id": owner_id
    },
    success: function(res) {
        console.log(res)
    },
    error: function(res) {
        console.log(res)
    }
})

IM即时通讯从0到1的实践,相关文章:

IM即时通讯-从0到1的实践(一)

IM即时通讯-项目框架搭建(二)

IM即时通讯-用户注册登录,及gin+JWT鉴权(三)<本文>

IM即时通讯-核心结构体设计(四)

IM即时通讯-消息id(五)

IM即时通讯-会话列表和会话信箱(六)

IM即时通讯-1.0版成果展示与后续扩展(七)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值