初试深浅:Node后台管理权限控制

后台管理系统中最简单的权限控制就是【登陆校验】。
在以前,包括现在的大部分中小型项目中依然是用的cookie、session进行校验。—— 这两个浏览器早期就实现了的API带给了我们很多便利。
fj

比如笔者在某vue项目后台设置了:

let tokenkey = 'a98sdyauefbh329'
app.get('/api/login', (req, res) => {
	const {
		username,
		password
	} = req.query
	if (username == 'yun' && password == '123456' || username == 'tim' && password == '123456') {
		res.json({
			code: 0,
			message: '登录成功',
			token: tokenkey + '-' + username + '-' + (new Date().getTime() + 60 * 60 * 1000)
		})
	} else {
		res.json({
			code: 1,
			message: '账号/密码错误'
		})
	}
})

对超级管理员请求成功后设置token —— 它其实在前端会保存到浏览器cookie里(前端判断code是否为0,若是,则调用api保存token),用于下一次登录时校验“在一定时间内是否已登录过”:

axios.interceptors.request.use(config=>{
	if(判断有没有token){
		config.headers.token=store.state.token
	}
	return config
})

这里笔者用了axios请求拦截:在再次发起请求时,判断有没有保存过token —— 如果有,就携带到header里返回给client。

fj

express中用session判断是否登录过

express有一个非常强大的模块:cookie-session

npm install cookie-session

使用时直接引入:

const cookieSession=require('cookie-session');

(function (){   //用立即执行函数防止污染全局
  var keys=[];
  for(var i=0;i<100000;i++){
    keys[i]='a_'+Math.random();
  }
  server.use(cookieSession({
    name: 'sess_id',
    keys: keys,
    maxAge: 20*60*1000  //20min
  }));
})();

在任意页面进入时判断:

  //检查登录状态
  router.use((req, res, next)=>{
    if(!req.session['admin_id'] && req.url!='/xxx'){ //没有登录且当前不是登录页(避免redirect黑洞)
      res.redirect('/admin/login');
    }else{
      next();
    }
  });

若是登录成功,则往session中添加相应值:

req.session['admin_id']=data[0].ID;

fj

koa中利用session保持登录状态

Koa是一个简洁的框架,把许多小功能都拆分成了中间件,用一个洋葱模型保证了中间件丰富的可拓展性,我们要使用Session来保持登录状态,就需要引用Session中间件。

koa中new koa() 只负责中间件,一切路由事宜全权交与new Router() 处理

npm install koa-session --save

使用时依然要先配置:

const session_signed_key = ["some secret hurr"];  // 这个是配合signed属性的签名key
const session_config = {
    key: 'koa:sess', /**  cookie的key。 (默认是 koa:sess) */
    maxAge: 4000,   /**  session 过期时间,以毫秒ms为单位计算 。*/
    autoCommit: true, /** 自动提交到响应头。(默认是 true) */
    httpOnly: true, /** 是否设置HttpOnly,如果在Cookie中设置了"HttpOnly"属性,那么通过程序(JS脚本、Applet等)将无法读取到Cookie信息,这样能有效的防止XSS攻击。  (默认 true) */
    signed: true, /** 是否签名。(默认是 true) */
    rolling: true, /** 是否每次响应时刷新Session的有效期。(默认是 false) */
    renew: false, /** 是否在Session快过期时刷新Session的有效期。(默认是 false) */
};
const Koa_Session = require('koa-session');   // 导入koa-session 

// 实例化
const app = new Koa();
const session = Koa_Session(session_config, app)
app.keys = session_signed_key;

// 使用中间件,注意有先后顺序
app.use(session);
app.use(async (ctx,next)=>{
    const databaseUserName = "yunxiaomeng";
    const databaseUserPasswd = "yunxiaomengnb";
    if (!ctx.session.logged) {  // 如果登录属性为undefined或者false,对应未登录和登录失败
        // 设置登录属性为false
        ctx.session.logged = false;

        // 如?nickname=post&passwd=123解析为{nickname:"post",passwd:"123"}
        let query = ctx.request.query;

        // 判断用户名密码是否为空
        if (query.nickname && query.passwd) {
            // 比对并分情况返回结果  
            if (databaseUserName == query.nickname) {  // 如果存在该用户名
                // 进行密码比对并返回结果 
                ctx.body = (databaseUserPasswd == query.passwd) ? "登录成功" : "用户名或密码错误";
                ctx.session.logged = true;
            } else {                    // 如果不存在该用户名
                ctx.body = "用户名不存在";
            }
        } else {
            ctx.body = "用户名密码不能为空";
        }
    } else {
        ctx.body = "已登录";
    }
})

fj

Koa2用jwt进行权限控制

const jwt = require('jsonwebtoken');
router.post('/login', async (ctx) => {
	const data = ctx.request.body;
	if(!data.name || !data.password){
		return ctx.body = {
			code: '2',
			data: null,
			msg: '参数不合法'
		}
	}
	const result = await userModel.findOne({
		name: data.name,
		password: data.password
	})
	if(result !== null){
		const token = jwt.sign({
			name: result.name,
			_id: result._id
		}, 'my_tokena', { expiresIn: '2h' });
		return ctx.body = {
			code: '0',
			data: token,
			msg: '登录成功'
		}
	}else{
		return ctx.body = {
			code: '2',
			data: null,
			msg: '用户名或密码错误'
		}
	}
});

然后前端可以在请求时获取token并保存:

axios.post('/login', {
		name: this.username,
		password: this.password
	}).then(res => {
		if(res.code === '0'){
			localStorage.setItem('token', res.data);
			this.$router.push('/');
		}else{
			alert(res.msg);
		}
	})

然后请求服务器端API的时候,把 token 带在请求头中传给服务器进行验证。每次请求都要获取 localStorage 中的 token,这样很麻烦,这里使用了 axios 的请求拦截器,对每次请求都进行了取 token 放到 headers 中的操作。

axios.interceptors.request.use(config => {
    const token = localStorage.getItem('token');
    config.headers.common['Authorization'] = 'Bearer ' + token;
    return config;
})
const koajwt = require('koa-jwt');

// 错误处理
//(后端)校验
app.use(koajwt({   //这个插件会自动找“请求头header”里的对应值
	secret: 'my_token'
}).unless({
	path: [/\/user\/login/]
}));

通过 app.use 来调用该中间件,并传入密钥 {secret: 'my_token'}unless 可以指定哪些 URL 不需要进行 token 验证。token 验证失败的时候会抛出401错误,因此如果需要添加错误处理,要放在 app.use(koajwt()) 之前,否则不执行。

如果请求时没有token或者token过期,则会返回401。

其实jwt自身也有校验api:jwt.verify(token,secret)
token就是传递过来的token;secret就是在设置token的时候使用到的密匙

猜你喜欢

转载自blog.csdn.net/qq_43624878/article/details/107196085
今日推荐