jwt

头像
用心
    阅读 7 分钟

    一、jwt

    1.1、介绍

    在之前的项目中,大部分网页是通过session来判断用户是否有权限来访问个别网页的,但是如果是SPA项目的话,前后端分离,客户请求的是前端,所以并不会保存数据到session,那该怎么办呢?针对这一问题,可以使用jwt来解决!

    JWT也就是JSON Web Token(JWT),是目前最流行的跨域身份验证解决方案。

    JWT的组成:一个JWT实际上就是一个字符串,它由三部分组成:头部(Header)、载荷(Payload)与签名(signature)。

    生成一个加密后的字符串,发送给客户端,客户端保存在浏览器中(cookie/localstorage/sessionstorage),在客户端请求敏感数据时,需要必须让客户端在头像携带加密的字符串(token)给服务器,服务器获取到token值后,进行解密,进行信息的比对,如果比对成功则返回数据,不对则不返回数据。

    1.2、jsonwebtoken

    nodejs中jsonwebtoken提供了一套(jwt)加密和解码的算法

    • 安装
    npm i -S jsonwebtoken
    npm i -S express cors mongoose
    
    • 加密解密
    var token=require("jsonwebtoken");
    //加密 生成密钥key
    var key=token.sign(数据,加密串);
    //解密 通过加密串将密钥解密还原
    var source=token.verify(key,加密串);
    • 加密
    const router = require('express').Router()
    const jwt = require('jsonwebtoken')
    // 设置一个jwt加密和解密时需要的key值
    const secretKey = 'afwefjwlefjlwjflewjjfew;jfwe;jfwe;jf;ejf;w'
    
    // 登录成功后,让保持登录者的状态,以前方案使用session,但是现在我们前后端分离,使用jwt
    
    // 接口登录操作
    router.post('/login', (req, res) => {
      let {username, password} = req.body
      res.send({
        code: 0,
        msg: 'ok',
        data: {
          // 加密
          token: jwt.sign({
            id: 1,
            username,
            // token过期时间 一般设置时长为2小时,有一些公司1天 1周 1个月
            // exp: Date.now() + 7200 * 1000
          }, secretKey)
        }
      })
    })
    • 解密
    router.get('/users', (req, res) => {
      const token = req.headers['token']
      res.send({
        code: 0,
        msg: 'ok',
        data: {
          id: 1,
          name: '张三',
          token: jwt.verify(token, secretKey)
        }
      })
    })
    
    module.exports = router;

    二、接口编写

    2.1、restfulapi

    一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。
    RestfulApi:面向资源

    image.png

    解决的问题

    • 降低开发的复杂性
    • 提高系统可伸缩性

    2.2、规范

    ①、协议:API与用户的通信协议,总是使用http或https协议。
    ②、域名:应该尽量将API部署在专用域名之下,例:http://api.demo.com
    ③、版本:应该将API的版本号放入URL,方便和直观,例http://api.demo.com/v1
    ④、路径
    在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词。例:https://api.example.com/v1/users
    ⑤、HTTP动词
    对于资源的具体操作类型,由HTTP动词表示

    GET(SELECT):从服务器取出资源(一项或多项)。
    POST(CREATE):在服务器新建一个资源。
    PUT/patch(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
    DELETE(DELETE):从服务器删除资源。
    例下面的方式来操作和获取数据
    GET /zoos:列出所有动物园
    GET /zoos/ID:获取某个指定动物园的信息
    POST /zoos:新建一个动物园
    PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
    DELETE /zoos/ID:删除某个动物园

    ⑥、过滤信息
    如果记录数量很多,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果。例:?limit=10:指定返回记录的数量
    ⑦、状态码
    服务器向用户返回的状态码和提示信息,常见的有以下一些(方括号中是该状态码对应的HTTP动词)

    200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
    201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
    202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
    204 NO CONTENT - [DELETE]:用户删除数据成功。
    400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
    401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
    403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
    404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
    406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
    410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
    422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
    500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。

    ⑧、返回结果
    针对不同操作,服务器向用户返回的结果应该符合以下规范

    GET /collection:返回资源对象的列表数组
    GET /collection/resource:返回单个资源对象
    POST /collection:返回新生成的资源对象
    PUT /collection/resource:返回完整的资源对象
    DELETE /collection/resource:返回一个空文档

    三、构建项目

    3.2、前端项目构建

    使用webpack来进行前端项目工程化构建

    • package.json
    {
      "name": "project",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "serve": "webpack-dev-server",
        "build": "webpack"
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "@babel/core": "^7.14.3",
        "@babel/preset-env": "^7.14.2",
        "art-template": "^4.13.2",
        "art-template-loader": "^1.4.3",
        "babel-loader": "^8.2.2",
        "clean-webpack-plugin": "^4.0.0-alpha.0",
        "copy-webpack-plugin": "^6.4.1",
        "core-js": "^3.13.0",
        "css-loader": "^5.2.6",
        "file-loader": "^6.2.0",
        "html-loader": "^1.3.2",
        "html-webpack-plugin": "^4.5.2",
        "style-loader": "^2.0.0",
        "ts-loader": "^6.2.2",
        "typescript": "^4.3.2",
        "url-loader": "^4.1.1",
        "webpack": "^4.46.0",
        "webpack-cli": "^3.3.12",
        "webpack-dev-server": "^3.11.2"
      },
      "dependencies": {
        "jquery": "^3.6.0"
      }
    }
    • webpack.config.js
    const path = require('path')
    // webpack插件,帮助webpack打包生成时,创建一个index.html文件
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    // 删除打包成的dist目录
    const { CleanWebpackPlugin } = require('clean-webpack-plugin')
    // 静态资源复制
    const CopyPlugin = require('copy-webpack-plugin')
    
    module.exports = {
      // 开启的模式,生产还是开发
      mode: 'development',
      // 开发工具配置 开发时配置 source-map 作用:代码出错了,可以帮我们定位到src目录中程序
      devtool: 'source-map',
      // 指定入口文件
      // 字符串
      entry: './src/main.js',
      // 出口
      output: {
        // 打包生成的文件路径 绝对地址
        path: path.resolve('dist'),
        // 打包生成后的主入口js文件
        filename: '[name].[hash:8].js'
      },
      resolve: {
        alias: {
          '@': path.resolve('src')
        },
        extensions: ['.js', '.json', '.art']
      },
      // 加载器
      module: {
        // 规则
        rules: [
          // 处理css
          {
            // 正则匹配loader解析文件扩展名
            test: /\.css$/i,
            // loader执行顺序
            // 执行顺序 写在一行:从右向左,写在多行:从下向上执行
            use: [
              "style-loader",
              "css-loader"
            ]
          },
          // 图片处理
          {
            test: /\.(png|jpeg|jpg|gif)$/i,
            use: [
              {
                loader: 'url-loader',
                options: {
                  // 图片小于8kb,就会被base64处理
                  limit: 1 * 1024,
                  name: 'images/[name].[ext]',
                  publicPath: '/'
                }
              }
            ]
          },
          // html中图片处理
          {
            test: /\.html$/,
            loader: ['html-loader']
          },
          // js兼容处理
          {
            test: /\.js$/,
            use: [
              {
                loader: 'babel-loader',
                options: {
                  presets: [
                    [
                      '@babel/preset-env',
                      {
                        // 按需加载
                        useBuiltIns: 'usage',
                        // 指定core-js版本
                        corejs: 3,
                        // 兼容性做到哪个版本的浏览器
                        targets: {
                          chrome: '75'
                        }
                      }
                    ]
                  ]
                }
              }
            ]
          },
          // 模板引擎解释
          {
            test: /\.art$/,
            use: ["art-template-loader"]
          }
        ]
      },
      // 插件
      plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
          // 模板
          template: path.resolve('public/index.html')
        }),
        // 复制静态资源 -- 直接复制不做任何处理
        new CopyPlugin({
          patterns: [
            {
              // 来源
              from: path.resolve('public/favicon.ico'),
              // 目标
              to: path.resolve('dist/favicon.ico')
            }
          ]
        })
    
      ],
      devServer: {
        port: 3000,
        // 显示编辑打包进度
        progress: true,
        // 安静模式,不显打包信息
        quiet: true,
        // 代理
        proxy: {
          '/api': {
            target: 'https://api.iynn.cn/film',
            changeOrigin: true,
            pathRewrite: {
              // '^/api': ''
            }
          }
        }
      }
    }
    • tsconfig.json
    {
      "compilerOptions": {
        "target": "es5",
        "module": "commonjs", 
        "strict": true
      }
    }
    • 前端路由

    使用一个第3方路由模块

    SME Router 是仿照 express 的风格编写的,前端路由库。所以 api 跟 express 有点类似。

    npm i -S sme-router
    https://sme-fe.github.io/website-router/zh/basic.html
    
    # 修复后的路由
    npm i -S wucode-router

    image.png


    用心
    1 声望0 粉丝

    « 上一篇
    webpack
    下一篇 »
    vue