简介
JSON Web Token(JWT)技术是一种编码字符串或令牌,包含无限的信息,URL安全,用于API身份验证。它是加密签名的。JWT身份验证的最大优点是令牌一旦发送,中间人就无法攻击和修改令牌。主要是JWT用于认证和发送机密信息。JWT使用了不同的算法(如HMAC、RSA)作为私钥/公钥进行数字签名。
JWT结构
- Header
- 主要包括算法和token类型,主要是jwt
- 有效载荷
- 包含数据信息
- 签名
- 它需要标头和有效负载进行编码。它验证令牌不会更改或受到攻击
package mainimport ("errors""fmt""net/http""os""time""github.com/dgrijalva/jwt-go""github.com/gin-gonic/gin")// Title JWT SERVER// JWT只能在过期时失效// JWT过期后需要重新登录,会导致用户体验差,可以通过Redis存储JWT,实现JWT刷新// JWT可能会被黑客劫持,实现一个一键注销功能,不需要等待过期/*** jwt.StandardClaims 声明*/type AuthRoleClaims struct {v interface{}Method *JWTMethodjwt.StandardClaims}type JWTMethod struct {ExpiresAt int64Issuer stringkey string}type JWTService interface {//生成TOKENGeneratorToken(phone string) string//验证TOKENValidatedToken(jwtToken string) (*jwt.Token, error)//刷新TOKENRefreshToken(jwtToken string) (*jwt.Token, error)//注销TOKENDeleteToken(jwtToken string) (*jwt.Token, error)}// jwt.NewWithClaims 生成JWT// jwt.NewWithClaims 方法根据 Claims 结构体创建 Token 示例。// param 1 jwt.SigningMethod {jwt.SigningMethodHS256, HS384, HS512}// param 2 StandardClaim 自定义类型/**type StandardClaims struct {Audience string `json:"aud,omitempty"`ExpiresAt int64 `json:"exp,omitempty"`Id string `json:"jti,omitempty"`IssuedAt int64 `json:"iat,omitempty"`Issuer string `json:"iss,omitempty"`NotBefore int64 f `json:"nbf,omitempty"`Subject string `json:"sub,omitempty"`}*/func (auth *AuthRoleClaims) GeneratorToken() string {claims := &AuthRoleClaims{v: auth.v,StandardClaims: jwt.StandardClaims{ExpiresAt: auth.Method.ExpiresAt,Issuer: auth.Method.Issuer,IssuedAt: time.Now().Unix(),},}token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)//编码为Stringjwt, err := token.SignedString([]byte(auth.Method.key))if err != nil {panic(err)}return jwt}func (auth *JWTMethod) ValidatedToken(jwtToken string) (*jwt.Token, error) {return jwt.Parse(jwtToken, func(token *jwt.Token) (interface{}, error) {if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {return nil, fmt.Errorf("Invalid token", token.Header)}return []byte(jwtToken), nil})}//全局变量var (START_PORT = "8080")type WebGroup struct {Version uintGroupPath string}type LoginInfo struct {Phone string `json:"phone"`Password string `json:"password"`}func ResponseStatus(status int) string {switch status {case 200:return "Success"case 400:return "User operatal error"case 500:return "Server Error"}return ""}func LoginServer() gin.HandlerFunc {return func(ctx *gin.Context) {login := &LoginInfo{}if err := ctx.ShouldBindJSON(login); err != nil {ctx.JSON(http.StatusBadRequest, gin.H{"msg": ResponseStatus(http.StatusBadRequest)})}secret := os.Getenv("SECRET")if secret == "" {ctx.JSON(http.StatusInternalServerError,errors.New("Error"))}claims := &AuthRoleClaims{v: login.Phone,Method: &JWTMethod{ExpiresAt: time.Now().Add(time.Second * 5).Unix(),Issuer: "user",key: secret,},}token := claims.GeneratorToken()ctx.JSON(http.StatusOK, gin.H{"jwtToken": token})}}func RegisterServer() gin.HandlerFunc {return func(ctx *gin.Context) {register := &LoginInfo{}if err := ctx.ShouldBindJSON(register); err != nil {ctx.JSON(http.StatusBadRequest, gin.H{"msg": ResponseStatus(http.StatusBadRequest)})}if len(register.Phone) != 11 || len(register.Password) <= 6 {ctx.JSON(http.StatusBadRequest, gin.H{"msg": ResponseStatus(http.StatusBadRequest)})}ctx.JSON(http.StatusOK, gin.H{"msg": ResponseStatus(http.StatusBadRequest)})}}///AUTH FUNCTIONSfunc InitializeAuthServer(engine *gin.Engine) {group := &WebGroup{Version: 1,GroupPath: "/login",}v1 := engine.Group(group.GroupPath)v1.POST("/login", LoginServer())v1.POST("/registher", RegisterServer())}func SetupRouter() *gin.Engine {//初始化Gin服务server := gin.New()//注册验证服务InitializeAuthServer(server)return server}func amain() {router := SetupRouter()router.Run(":" + START_PORT)}
