• node+vue,实战demo


    该项目功能

    页面内容:
    1.注册
    2.登录
    3.退登、修改密码/修改昵称
    4.列表页(可新增,删除,修改,查询)
    5.子账号页(可增,删,改,查)==》仅对超级管理员开放
    
    用到技术:
    1.反向代理
    2.数据库建表,请求mysql数据库
    3.进行node模块化开发,分模块处理请求()
    
    具体功能:
    1.生成验证码
    2.token:前端用uuid加密生成token实现验证码一一对应
    3.用redis(可支持:键/值对,哈希表,链表,集合)缓存token以及用户信息,并设置过期时效
    
    redis使用:
    1.先跑起来redis服务:到redis文件目录下:redis-server redis.window.conf
    2.在打开可视化工具(redis desktop manager)查看
    

    **前端代码 https://github.com/miaSlady/modular_html.git **
    **node后台代码 https://github.com/miaSlady/modular.git **

    具体实现过程

    数据库部分

    数据库搭建

    1.建立读书计划表





    2.建立用户列表


    后台node部分

    1.安装以下依赖

     "koa": "^2.12.0",
      "koa-bodyparser": "^4.3.0",
      "koa-router": "^8.0.8",
      "koa-session": "^6.0.0",
      "koa2-cors": "^2.0.6",
      "mysql": "^2.18.1",
      "redis": "^3.0.2",
      "svg-captcha": "^1.4.0"
      "crypto": "^1.0.1"
    
    koa 写后台;mysql连接服务器;svg-captcha生成二维码;redis写token校验;crypto配合redis使用
    
    2.配置跨域
    1.在公共方法utils里头新建中间件koa-cors.js
    注:1.allowDomain允许访问的域名
        2.对options进行处理:method = OPTIONS 时, 属于预检(复杂请求), 当为预检时, 可以直接返回空响应体   
    module.exports = async (ctx, next) => {
      const allowDomain=[
        "http://172.16.0.128:1818/",
        "http://172.16.0.25:1818/",
        "http://localhost:1818/",
      ]
      if(allowDomain.includes(ctx.header.referer) || allowDomain.includes(ctx.header.origin + '/')){
        // ctx.set('Access-Control-Allow-Origin', '*'); //允许来自所有域名请求(不携带cookie请求可以用*,如果有携带cookie请求必须指定域名)
        ctx.set("Access-Control-Allow-Origin", ctx.header.origin); // 只允许指定域名http://localhost:8080的请求
    
        ctx.set('Access-Control-Allow-Methods', 'OPTIONS, GET, PUT, POST, DELETE'); // 设置所允许的HTTP请求方法
    
        ctx.set('Access-Control-Allow-Headers', 'x-requested-with, accept, origin, content-type,token'); // 字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段.
        // 服务器收到请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。
    
        ctx.set('Content-Type', 'application/json;charset=utf-8'); // Content-Type表示具体请求中的媒体类型信息
    
        ctx.set('Access-Control-Allow-Credentials', true); // 该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。
        // 当设置成允许请求携带cookie时,需要保证"Access-Control-Allow-Origin"是服务器有的域名,而不能是"*";
    
        ctx.set('Access-Control-Max-Age', 300); // 该字段可选,用来指定本次预检请求的有效期,单位为秒。
        // 当请求方法是PUT或DELETE等特殊方法或者Content-Type字段的类型是application/json时,服务器会提前发送一次请求进行验证
        // 下面的的设置只本次验证的有效时间,即在该时间段内服务端可以不用进行验证
    
        ctx.set('Access-Control-Expose-Headers', 'myData'); // 需要获取其他字段时,使用Access-Control-Expose-Headers,
        // getResponseHeader('myData')可以返回我们所需的值
        /*
        CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:
            Cache-Control、
            Content-Language、
            Content-Type、
            Expires、
            Last-Modified、
            Pragma。
        */
    
        /* 解决OPTIONS请求 */
        if (ctx.request.method == 'OPTIONS') {
            ctx.status = 200;
        } else {
            await next();
        }
      }else{
        ctx.throw(500);
      }
    
    };
    
    3.连接服务器
    1.在middlewares文件下创建databases.js。
    const mysql=require("mysql");
    
    const db=mysql.createConnection({
      host:"localhost",
      port:3306,
      user:'root',
      password:'123456',
      database:'modular',//数据库名
      multipleStatements: true,//可执行多条sql语句
    });
    
    const connectDb=function(){
      db.connect(err=>{
        if(err) throw err;
        console.log("连接成功");
      })
    }
    
    module.exports={
      db,
      connectDb
    }
    
    > 暴露出db用于sql查询,connectDb在app.js中进行全局引入
    
    2.在app.js添加
    
    const {connectDb}=require('./middlewares/databases')
    connectDb();
    
    
    3.分模块管理路由

    注:
    (1)app.js写全局注入
    (2)controller.js里头写接口封装
    (3)controllers 里头写各个模块调用的接口封装
    1.在app.js
    // 导入controller middleware:
    const controller = require('./controller');//对路由分模块处理
    controller(app);
    2.在controller.js(具体写法查看github项目:https://github.com/miaSlady/modular.git)
    module.exports = function (app,dir) {
        let
            controllers_dir = dir || 'controllers',
            router = require('koa-router')();
        addControllers(router, controllers_dir);
        //token拦截中间件
        app.use(async (ctx,next)=>{
          ...
        })
        app.use(router.routes());
        
        // return router.routes();
    };
    3.token拦截中间件配置
    配置逻辑:
    (1)除获取验证码接口,其他接口需携带token
    (2)注册、登录接口无需校验,直接去调用接口await next(),会在接口处去校验token、code是否匹配
    (3)其他接口需校验token判断code上传是否正确(先判断token是否存在,再获取用户信息),在ctx里头存用户信息,便于其他接口调用ctx.state.user=user;
     //token拦截中间件
        app.use(async (ctx,next)=>{
            var url=ctx.request.URL.pathname;
            if(url!='/login/code'){//非获取验证码(需携带token)
                const {token}=ctx.request.header;
                let response={
                    code:401,
                    success:false,
                    msg:'登录失效,请重新登录'
                };
                if(token){
                    ctx.state.token=token;
                    return new Promise((res,req)=>{
                        console.log(3)
                        if(url!='/login/signUp' && url!='/login/login'){//不是注册且不是登录进行token校验
                            client.hexists('codeUserInfo',token, (err, data)=>{//判断token是否失效
                                console.log(4,data)
                                if(data){//token未失效获取用户信息  
                                    client.hgetall('codeUserInfo', (err, obj)=>{
                                        let user=obj[token];
                                        user=JSON.parse(user);
                                        ctx.state.user=user;
                                        res(true)
                                    });
                                }else{//token失效
                                    res(false)
                                }
                            }) 
                        }else{//注册或登录无需进行token校验
                            res(true)
                        }
                    }).then(async(bool)=>{
                        if(bool){
                            console.log('调接口去');
                            await next();
                        }else{
                            ctx.response.body=response 
                        }
                    })
                }else{//没携带token
                    ctx.response.body=response
                }
            }else{//获取验证码code
                await next();
            }
        })
    
    
    4.用基于uuid生成随机数用于token
    const uuidv4 = require('uuid/v4');
    token=uuidv4()
    
    5.生成验证码
    const svgCaptcha = require('svg-captcha');//生成验证码
    let captcha = svgCaptcha.create({
        size:4,//验证码个数
        fontSize:50,//验证码字体大小
        135,//宽度
        heigth:47,//高度
        background:'#cc9966'//背景大小
      });
    
      ctx.response.type="image/svg+xml";//设置返回的数据格式
      let token=uuidv4(),obj={};
      obj[token]=captcha.text;
      client.hmset('codeVerify', obj, redis.print);
      client.expire('codeVerify',180);//3分钟自动过期
    
    6.redis存取(我用的hash)
    var redis = require('redis')//中间件:缓存哈希表(1.注册/登录判断code是否输入正确;2.登录用token对应用户信息)
    var client = redis.createClient(6379, '127.0.0.1')
    client.hmset('codeUserInfo', userInfo , redis.print);//存
    client.expire('codeUserInfo',24*60*60);//1天自动过期(设置过期时间)
    client.hgetall('codeVerify', (err, obj)=>{//获取
          console.log('我获取到了',obj);
          if(err){
            rej(err)
          }else{
            res(obj)
          }
        })
    client.hexists('codeUserInfo',token, (err, data)=>{//查存在
          if(data){
            client.hdel('codeUserInfo', token,async (err,data)=>{//删除
              res()
            });
          }else{
            res()
          }
        });
    
    7.登录逻辑
    (1)调接口获取验证码,后台在验证码接口用uuid生成随机数作为token返给前端,存在redis里头的codeVerify对象(自己可命名,设置时效3分钟,可自己定),键为token(这串uuid加密的随机数),值为code的值
    (2)前端登录/注册请求头带token请求接口,后台去redis里头的codeVerify校验code是否正确,若正确获取用户信息,存在redis里头的codeUserInfo对象(键token,值用户信息,设置时效3天,可自己定),以后每个接口请求头携带token。
    
  • 相关阅读:
    yii2.0 干货
    VLD opcodes 在线查看
    定长顺序串的实现
    循环队列
    oracle--DG初始化参数
    oracle --工具 ODU
    Oracle RAC 修改SPFILE路径 文件查看
    oracle 错误 ORA-00020问题解析
    oracle 错误 TNS-01190与oracle 登入没反应操作
    Oracle--RMAN Recover 缺失的归档操作
  • 原文地址:https://www.cnblogs.com/miaSlady/p/13132356.html
Copyright © 2020-2023  润新知