• wordpress CMS主题:ssmay主题 wordpress CMS主题:ssmay主题
  • 首页 > 前端开发 > 除了cookie,你还可以用jwt(json web token)!

    除了cookie,你还可以用jwt(json web token)!

    作者: 分类:前端开发 点击: 586 次
    wordpress CMS主题:ssmay主题

      扫描下面的二维码,“关注”我的百家号。

      1. 认识jwt(json web token)

      • jwt是为了在网络应用环境传递声明而执行的一种基于json的开放标准。
      • jwt被用来在身份提供者和服务提供者间传递被认证的用户身份信息,简单来说,就是用来验证身份的手段,例如登录校验,像我们之前用的cookie。
      • jwt可以使用HMAC算法或者是RSA的公私秘钥对来进行签名,来保证信息的可靠性。

      2. 应用场景

      在例如身份验证场景中,用户一旦登录,接下来的每个请求都会包含jwt,用来验证身份信息。由于通信双方使用jwt对数据进行编码,它的信息是经过签名的,所以可以确保信息的安全性。

      3. jwt对比cookie

      cookie缺点

      • 客户端发请求给服务器,服务器种植cookie后,每次请求都会带上cookie,浪费带宽
      • cookie不能跨服务器访问,不支持跨域
      • 服务器要对登录的用户对象进行存储,浪费服务器内存

      jwt优点

      • 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和验证,所以需要保护好。

      5. 举个栗子

      express+vue+mongoose
      后端app.js,包括注册,登录,获取订单接口

      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)
      

      数据库页面

      // 操作数据库
      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.js

      module.exports = {
          'DB_URL': 'mongodb://localhost:27017/jwt',
          'secret': 'jeffywin'//秘钥 加盐
      }
      

      前台界面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
      https://github.com/jeffywin/jwt

      本文转载于猿2048:除了cookie,你还可以用jwt(json web token)!



      欢迎“关注”我的百家号。

      头条二维码
      加入我的QQ群
      头条二维码
      关注我的百家号

    文章作者:sunny
    本文地址:http://wanlimm.com/77202006218390.html
    版权所有 © 转载时必须以链接形式注明作者和原始出处!

    上一篇:
    下一篇:
    wordpress CMS主题:ssmay主题

    或许你会感兴趣的文章:

    发表评论

    电子邮件地址不会被公开。 必填项已用*标注

    This site uses Akismet to reduce spam. Learn how your comment data is processed.