Jwt用户认证的优点

635 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

JSON Web token 简称 jwt 是一种轻量级的用户认证机制。可以取代cookie或session的用户认证方式。

image

优点:

  1. 服务端可以不缓存用户信息

  2. 可以跨域 什么是跨域

  3. 可防护CSRF攻击 CSRF攻击

  4. 有签名验证机制

JWT要求有一个秘钥,还有一个算法,秘钥和算法可以用来生成签名的保证jwt不被篡改

  1. 自带超时信息

JWT的base64明文机制,可以使得web页面可以轻易获得超时信息

可以做什么?

  1. 认证用户的登录状态
  2. 授权用户特定操作或者获取特定资源
  3. 跨域传递用户授权信息

不可以做什么?

  1. 持久化用户信息
  2. 存储用户敏感信息例如密码,卡号,电话等(jwt是明文保存用户信息Playload)
  3. 传递大量信息(这个放Cookie不香么)

可以完全取代session么?

你觉得可能么?session是在服务端存储用户信息,本身就有服务端安全的优势,存储内容也没有限制。 都说了jwt只是轻量级用户授权机制,为啥要干重活呢?jwt + session不可以么?说实话在url中传递session真是蠢透了!

优雅的使用axios接入jwt

自动拦截注入jwt授权信息,服务端jwt验证失败时(401)直接跳转回登录页面

**
 * 拦截器,为请求头添加jwt信息
 */
let http = axios.create({
  baseURL: 'http://xxx.xxx.xxx.xxx/blog',
  timeout: 10000
})

http.interceptors.request.use(
  config => {
    if (storage.get('JWT_TOKEN')) { // 判断是否存在token,如果存在的话,则每个http header都加上token
      config.headers.Authorization = `token ${storage.get('JWT_TOKEN')}`
    }
    return config
  },
  err => {
    return Promise.reject(err)
  }
)
http.interceptors.response.use(
  response => {
    return response
  },
  error => {
    if (error.response) {
      console.log('axios:' + error.response.status)
      switch (error.response.status) {
        case 401:
          // 返回 401 清除token信息并跳转到登录页面
          storage.remove('JWT_TOKEN')
          router.replace({
            path: 'login',
            query: {redirect: router.currentRoute.fullPath}
          })
      }
    }
    return Promise.reject(error.response.data) // 返回接口返回的错误信息
  }
)

服务端校验代码(golang)

#添加依赖
go get github.com/dgrijalva/jwt-go
---
package utils

import (
	"fmt"
	"strings"
	"time"

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

type jwtCustomClaims struct {
	jwt.StandardClaims

	// 追加自己需要的信息
	Uid      int64  `json:"uid"`
	Username string `json:"username"`
}

func GenJwt(userid int64, username, secret string) string {
	claims := &jwtCustomClaims{
		jwt.StandardClaims{
			ExpiresAt: int64(time.Now().Add(time.Hour * 2).Unix()),
			Issuer:    username,
		},
		userid,
		username,
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	jwtStr, _ := token.SignedString([]byte(secret))
	return jwtStr
}

func CheckJwt(jwtStr, secret string) (int64, error) {
	args := strings.Split(jwtStr, " ")
	if len(args) == 2 && args[0] == "token" {
		jwtStr = args[1]
	} else {
		return -1, errors.New("Wrong type of jwt token!")
	}
	claims := &jwtCustomClaims{}
	token, err := jwt.ParseWithClaims(jwtStr, claims, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return -1, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
		}
		return []byte(secret), nil
	})
	if err != nil {
		return -1, err
	}
	return claims.Uid, token.Claims.Valid()
}

服务端校验代码(java)

别人写过了传送门