除了cookie,你還能夠用jwt(json web token)!

1. 認識jwt(json web token)

  • jwt是爲了在網絡應用環境傳遞聲明而執行的一種基於json的開放標準。
  • jwt被用來在身份提供者和服務提供者間傳遞被認證的用戶身份信息,簡單來講,就是用來驗證身份的手段,例如登陸校驗,像咱們以前用的cookie。
  • jwt可使用HMAC算法或者是RSA的公私祕鑰對來進行簽名,來保證信息的可靠性。

2. 應用場景

在例如身份驗證場景中,用戶一旦登陸,接下來的每一個請求都會包含jwt,用來驗證身份信息。因爲通訊雙方使用jwt對數據進行編碼,它的信息是通過簽名的,因此能夠確保信息的安全性。css

3. jwt對比cookie

cookie缺點vue

  • 客戶端發請求給服務器,服務器種植cookie後,每次請求都會帶上cookie,浪費帶寬
  • cookie不能跨服務器訪問,不支持跨域
  • 服務器要對登陸的用戶對象進行存儲,浪費服務器內存

jwt優勢ios

  • jwt是不基於狀態的,不須要每次請求都帶上token,節約流量
  • 服務器不須要佔用內存,信息相對於可靠些
  • 能夠跨服務端,能夠共用

4. jwt結構

  • Header頭部:{typ:'jwt',alg:'HS256'} alg:當前用的什麼算法加密的;使用Base64Url編碼組成了JWT結構的第一部分
  • PlyLoad負載:存放有效信息的地方
  • Signature簽名:建立簽名須要使用編碼後的header和payload以及一個祕鑰;例如若是但願使用HMAC SHA256算法,那麼簽名應該使用下列方式建立 HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

完整的jwt格式的輸出是以 . 分隔的三段Base64編碼 密鑰secret是保存在服務端的,服務端會根據這個密鑰進行生成token和驗證,因此須要保護好。git

5. 舉個栗子

express+vue+mongoose 後端app.js,包括註冊,登陸,獲取訂單接口github

let express = require('express')
let bodyParser = require('body-parser')//中間件
let jwt = require('jwt-simple')//jwt庫
//數據庫
let User = require('./model/user')
//監聽函數
let app = express()
let {secret} = require('./config')
//中間件必定是函數,處理髮回來的json類型,還有text,urlencoded(a=b&c=d)
app.use(bodyParser.json())

//防止跨域 request請求 response響應
app.use(function(req, res, next){
    res.setHeader('Access-Control-Allow-Origin','*');//簡單點,接收全部
    res.setHeader('Access-Control-Allow-Headers','Content-type,Authorization');
    res.setHeader('Access-Control-Allow-Methods','GET,POST,DELETE,PUT,OPTIONS');
    if(req.method === 'OPTIONS') {
        res.end()
    }else {
        next()
    }
})

//註冊
app.post('/reg', async function(req, res, next){
    let user = req.body;
    try {
        user = await User.create(user) //在數據庫中插入數據
        res.json({
            code: 0,
            data: {
                user: {
                    id: user._id,
                    username: user.username
                }
            }
        })
    } catch (error) {
        res.json({
            code: 1,
            data: '註冊失敗'
        })
    }  
})
//登陸
app.post('/login', async function(req,res,next){
    let user = req.body;
    user = await User.findOne(user)//數據庫中查找
    if(user) {
        let token = jwt.encode({//編碼
            id: user._id,
            username: user.username
        },secret);
        res.json({//返回信息
            code: 0,
            data: { token }
        })
    }else {
        res.json({
            code: 1,
            data: '用戶不存在'
        })
    }
}) 
// 用戶校驗 中間件
let auth = function(req, res, next){
    //post模擬時 添加Headers Authorization: Bearer token的值
    let authorization = req.headers['authorization']
    if(authorization) {
        let token = authorization.split(' ')[1];
        try {
            //看token是否合法,解碼,若是串改過token就解不出來,進入異常頁面
            let user = jwt.decode(token, secret);
            req.user = user;//後面就能夠拿到user,中間件用法 
            next();//下一步
        } catch (error) {
            console.log(error)
            res.status(401).send('Not Allowed')
        }
    } else {
        res.status(401).send('Not Allowed');
    }
}
//發送請求,看看能不驗證成功auth,若是能夠拿到返回數據
app.get('/order', auth, function(req,res,next){
    res.json({
        code: 0,
        data: {
            user: req.user
        }
    })
})
app.listen(3000)
複製代碼

數據庫頁面web

// 操做數據庫
let mongoose = require('mongoose');
let {DB_URL} = require('../config');

mongoose.connect(DB_URL,{useNewUrlParser:true})

/**
  * 鏈接成功
  */
 mongoose.connection.on('connected', function () {    
    console.log('Mongoose connection open to ' + DB_URL);  
});    

/**
 * 鏈接異常
 */
mongoose.connection.on('error',function (err) {    
    console.log('Mongoose connection error: ' + err);  
});

//建立Schema數據模型
let UsrSchema = new mongoose.Schema({
    username: String,
    password: String
});
module.exports = mongoose.model('User', UsrSchema);
複製代碼

axios簡單封裝算法

import axios from 'axios'
import router from '../src/router'
axios.defaults.baseURL = 'http://localhost:3000'
//axios 攔截器對拿到的數據進行攔截
axios.interceptors.response.use(function(res){
    if(res.data.code !== 0) {
        return Promise.reject(res.data.data)
    }
    return res.data;
},res=>{
    if(res.response.status === 401){ // 沒權限跳到登陸頁
        router.history.push('/login');
    }
    return Promise.reject('Not Allowed');
});

//對發送的請求統一加上token,來驗證是不是本人登陸
axios.interceptors.request.use(function(config){
    let token = localStorage.getItem('token')
    if(token) {
        config.headers.Authorization = `Bearer ${token}`
    }
    return config;
})

export default axios
複製代碼

config.jsmongodb

module.exports = {
    'DB_URL': 'mongodb://localhost:27017/jwt',
    'secret': 'jeffywin'//祕鑰 加鹽
}
複製代碼

前臺界面vue-cli腳手架,沒什麼說的,登陸界面vue-cli

<template>
  <div class="main">
    <div class="item">
      <div style="width:100px">登陸頁</div> 
      <input type='text' v-model='user.username'/>
    </div>
    <div class="item">
      <div style="width:100px">密碼</div> 
      <input type='text' v-model='user.password'/>
    </div>
    <button @click="login">提交</button>  
  </div>
</template>

<script>
import axios from '../../utils/axios'
export default {
  data() {
      return {
        user: {
          username: '',
          password: ''
        }
      }
  },
  methods: {
    login() {
      axios.post('/login',this.user).then(res => {
        localStorage.setItem('token', res.data.token)//登陸後存儲token
        this.$router.push('/order')
      })
    }
  }
}
</script>

<style scoped lang="scss">
.main {
  margin: 0 auto;
  width: 300px;

  .item {
    display: flex;
    margin-bottom: 10px;
  }
  }
</style>

複製代碼

order界面數據庫

<template>
  <div class="order">
    <h1>This is an order page</h1>
    {{username}}//若是登陸成功,跳轉order界面,拿到登陸的用戶
  </div>
</template>

<script>
import axios from '../../utils/axios'
  export default {
    data() {
      return {
        username: ''
      }
    },
    mounted() {
      axios.get('/order').then(res => {
        this.username = res.data.user.username
      })
    },
  }
</script>

複製代碼

源碼在本人github github.com/jeffywin/jw…

相關文章
相關標籤/搜索