Node.js web常用技术

本文详细介绍了HTTP协议中的无状态特性以及如何通过Cookie和Session实现用户身份认证。阐述了Cookie的工作流程,包括设置、传输和安全注意事项,同时讲解了Session的原理及其实现。文中还通过实例展示了登录、验证和退出过程,强调了数据安全和会话管理的重要性。
摘要由CSDN通过智能技术生成

状态管理(了解、后端)

由于是无状态协议,为了保障安全,就需要cookie和session。

它按照下面的流程来认证客户端的身份

  1. 客户端登录成功后,服务器会给客户端一个出入证(令牌 token)

  2. 后续客户端的每次请求,都必须要附带这个出入证(令牌 token)

cookie

存基础用户名,当需要访问重要的东西,还需要再次验证登录等操作。每访问一次网站,都会给客户端一个cookie,存在客户端的卡包中(可以存放多个,可以自动出示,可以准确出示,可以自动管理,过期自动移除),是全部以键值存在的,等下次进入就会识别到cookie是那个用户。

当浏览器向服务器发送一个请求的时候,它会瞄一眼自己的卡包,看看哪些卡片适合附带捎给服务器。

条件(同时满足)

1、cookie没有过期

2、cookie中的域和这次请求的域是匹配的

3、cookie中的path和这次请求的path是匹配的

4、验证cookie的安全传输

  • 如果cookie的secure属性是true,则请求协议必须是https,否则不会发送该cookie

  • 如果cookie的secure属性是false,则请求协议可以是http,也可以是https

具体加入的方式是,浏览器会将符合条件的cookie,自动放置到请求头中

cookie中包含了重要的身份信息,永远不要把你的cookie泄露给别人!!!否则,他人就拿到了你的证件,有了证件,就具备了为所欲为的可能性

cookie 中间件

步骤:

1、安装中间件。

脚手架一般都自动已经生成了。

npm i cookie-parser

 2、在登录成功时,给浏览器一个cookie。

 

/* 登录 */
router.get('/login', async function (req, res ) {
    let {name,psw} = req.query; //获取请求数据
    let arr= await serviceAdim.find();//得到数据库所有账号密码
    let result = arr.filter(item => item.name == name && item.psw == psw)[0]; //得到结果
    if(result){
  //cookie的保存是  键值对  key=value
    // res.header("set-cookie",`token=${result._id};path=/;domain=127.0.0.1;max-age=3600;httpOnly`);
    //如果有返回值,则说明登录成功
    //将用户id保存到cookie中
    //使用cookie-parser中间件的方法
    //参数一:cookie名称
    //参数二:cookie的值
    //参数三:可选配置对象
    res.cookie("token", result._id, {
        path: "/",
        domain: "127.0.0.1",
        maxAge: 7 * 24 * 3600 * 1000, //毫秒数,可以不写,就默认是浏览器会话时间。
        });
        res.send(resultUtil(result,0,"登录成功",0));        
    }
    else{
        res.send(resultUtil(result,0,"登录失败",1));
    }
  });

 

3、每次使用需要验证,需要一个专门进行验证的文件来进行判断。

注意:路由地址是/user/:id,但是用户真实传过来的地址是/user/1 /user/2,因此需要一个转换路径的中间件,path-to-regexp。

 注:先下载在引入,中间件引入格式必须是var{pathToRegexp} = require("path-to-regexp");不然接收不到。

var{pathToRegexp} = require("path-to-regexp");
/* 判断每次请求,对应user里的操作 */
let needToToken = [
    {method:"GET",path:"/user"},///user是路由里面设置的路径入口
    {method:"GET",path:"/user/:id"},
    {method:"PUT",path:"/user/:id"},
    {method:"DELETE",path:"/user/:id"},
    {method:"POST",path:"/user/add"},
];

//注意:路由地址是/user/:id
//但是用户真实传过来的地址是/user/1  /user/2

module.exports = function(req,res,next){
    console.log(req.method,req.path);//得到请求的方式和路径

    let apis = needToToken.filter(item=>{
        let reg = pathToRegexp(item.path);//把路径 /user/2转换为/user/:id
        //验证地址是不是需要验证的地址
        let flag = reg.test(req.path);

        return item.method === req.method && flag;
    });
    //请求的地址在验证的数据里没有,就直接通过
    if(apis.length <= 0){
        next();
        return;
    }
//得到登录的token
    let token = req.cookies.token;

    if (!token) {//如果没有就需要重新登录
        res.send({code:1,msg:"请先登录",data:null});
        return;
    }
    next();//有就通过。
}

4、在总的路由文件引入这个验证文件。

const tokenMiddleware =  require("./tokenMiddleware.js");

router.use(tokenMiddleware);

 

5、在识别没有cookie码直接跳转到登录注册页面。

如果通过地址栏直接进入导航,需要进行判断,因为cookie全是;分割的键值对需要转成数组,再去查找是否有一个叫Token的键,然后的它对应的值,就是id,有的化就和登录一样,进行验证,只不过通过比对Id,如果没有就直接跳转到登录页面。

handle(){
        let layer = layui.layer;
        let token = "";   
        let cookies = document.cookie;//得到所有cookie,获取的到的cookie可能不止一个,每一个cookie是用;进行分割的,token=xxx;user=xxxx;id=xxxx;
        let cookieArr = cookies.split(";");//转换成数组   
        for(let i=0; i<cookieArr.length; i++){
            let item = cookieArr[i];            
            let arr = item.split("="); //每一个cookie都是一个键值对 xxx=xxxxx,在分割成数组
            if(arr[0] === "token"){//键等于token,就代表有,然后把后面的赋给声明的字符串。
                token = arr[1];
                break;
            }
        }
        if(!token){ //如果token都没有,那么肯定没有登录,就跳转到登录
            location.hash = "#/login";
            return;
        }
        else{            
            $.ajax({//如果有token当然还需要到后端进行验证
                url:"/api/adim/verify/woami",
                type:"GET",
                success:function(res){
                    if(res.code === 0){
                        $("#username").text(res.data.name);//把登录名给添加在页面上
                    }
                    else{
                        location.hash = "#/login";
                    }
                }
            });

/* 点击退出 */
            $("#logout").on("click",function(){
                $.ajax({
                    url:"/api/adim/verify/loginOut",
                    type:"GET",
                    success:function(res){
                        if(res.code === 0){
                            alert("退出成功")
                            location.hash = "#/login";
                        }
                    }
                });
            });

        } 
    }

 

6、同样在后端路由里面也需要相应的设置。

由于都是 router.get,为了区分需要加一个分路径,不然会识别进入上面的注册路由,得到请求过来的token,没有就跳转登录,有就比对Id验证。

 

 /* 验证登录 路径要改一下,不然会默认是上面的注册*/
  router.get("/verify/woami",async function(req,res,next){
    let token = req.cookies.token;
    if(!token){//没有token
        res.send({code:1,msg:"请先登录",data:null});
    }
    else{
        let arr= await serviceAdim.find();//得到数据库所有账号密码
        let result = arr.filter(item => item._id == token)[0]; //得到结果
        console.log(result);
        if(!result){
            res.send({code:1,msg:"请先登录",data:null});
        }
        else{
            res.send({code:0,msg:"验证成功",data:result});
        }
    }
});

7、退出。

同样也是导航页面的事件,然后再路由也需要一个相应路径,在后台进行操作。

 前台
   
    $("#logout").on("click",function(){
                $.ajax({                    url:"/api/adim/verify/loginOut",
                    type:"GET",
                    success:function(res){
                        if(res.code === 0){
                            alert("退出成功")
                            location.hash = "#/login";
                        }
                    }
                });
            });
            
    后台
    
    /* 退出 */
router.get("/verify/loginOut",function(req,res){
    res.cookie("token", ""(这里token的值只接改成空字符串), {
        path: "/",
        domain: "127.0.0.1",
        maxAge: -1, //改成-1
        });
    res.send({code:0,msg:"退出成功",data:null});
});

session(前端一般拿不到这个值,只能得到session id)

不能设置保存时间,是浏览器会话时间。

cookie 虽然很方便,但是使用 cookie 中的所有数据在客户端就可以被修改,数据非常容易被伪造,那么一些重要的数据就不能存放在 cookie 中了,而且如果 cookie 中数据字段太多会影响传输效率。为了解决这些问题,就产生了 session,session 中的数据是保留在服务器端的。

 原理:

通过浏览器访问,后台生成一个id和内容,把随机生成的id发给浏览器,但是实际上的具体信息都存在后台,浏览器得到的只是一个随机的id,当会话结果,id自动失效,这样就保障了信息的安全性。

1、后端安装。

npm i express-session

 2、在后端入口文件并要引用并设置。

//引入express-session中间件
const session = require("express-session");
app.use(session({
  secret:"lovo",
  name:"sessionid",
  resave:true,
  saveUninitialized:true
}));

 3、当用户登录成功之后,就可以记录session信息,因此在登录的路由代码中加入session。

router.post('/login', async function (req, res) {
    let {name,psw} = req.body; //获取请求数据
    let arr= await serviceAdim.find();//得到数据库所有账号密码
    let result = arr.filter(item => item.name == name && item.psw == psw)[0]; //得到结果
    if(result){
    /* session方式 */
    req.session.loginUser = result;//loginUser自己取名
        res.send({code:0,msg:"登录成功",data:result});        
    }
    else{
        res.send({code:1,msg:"登录失败",data:null});
    }
  });

 4、在需要验证的路由中,判断是否有session,并且session对象中是否有loginUser对象即可,我们可以在之前的中间件中,直接处理session。

   /* session处理方式 */
    if (req.session && req.session.loginUser) {//进入中间件判断,是否有.loginUser
        //说明已经登录过了
        next();
    } else {
        res
        .status(403)
        .send("你没有权限这么做,请点击<a href='http://127.0.0.1:8888/login.html'>这里</a>先登录");
        return;
    }

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值