express-security v0.7.8
express-security
一套Express中间件,轻量,用于根据当前用户是否登陆、及其拥有的角色来拦截请求。
使用说明
目前使用AuthenticationInterceptor、 AuthorizationInterceptor、AuthInterceptor 类作为对外统一接口。三个类的职责为:
AuthenticationInterceptor: 负责认证检查AuthorizationInterceptor:负责授权检查AuthInterceptor:负责认证和授权检查,只是以上两个类的包装
- 根据需要,实例化一个
AuthenticationInterceptor、AuthorizationInterceptor、或者AuthInterceptor拦截器 - 使用拦截器拦截请求
默认情况
默认的实现是基于session机制:
- 默认情况下,需要确保
req.session的可用性。 - 默认情况下,对客户端的用户名判断是通过
req.session.username实现的。如果要定制,需要自行提供登陆检查器。 - 默认情况下,对客户端的角色判断是通过
req.session.roles实现的。如果要定制,需要自行提供角色访问器。
所以,这时候往往需要安装第三方模块保证session可用,比如使用express-session中间件:
> npm install express-session --save使用之前需要实例化出一个对象:
// initialize a authentication-interceptor
const authenInterceptor=new AuthenticationInterceptor();
// initialize a authorization-interceptor
const authorInterceptor=new AuthorizationInterceptor();
// or just initialize a auth-interceptor
const interceptor=new AuthInterceptor();自定义配置
尽管默认的配置是基于session的,但是,AuthInterceptor、AuthenticationInterceptor、和AuthorizationInterceptor的检查机制并不和 session 耦合在一起。 通过提供自定义登陆检查器、角色访问器,完全可以丢掉 session 。
登陆检查器:函数对象,接收请求req参数,同步返回(或者以等价的异步的方式“返回”)当前用户是否登陆的boolean值,角色访问器: 函数对象,接收请求req参数,同步返回(或者以等价的异步的方式“返回”)当前用户所拥有的角色列表。放心,拦截器只会对“返回”的角色列表读操作。
可以通过AuthenticationInterceptor、AuthorizationInterceptor实现自定义:
// 认证拦截器
const authenticationInterceptor=new AuthenticationInterceptor(
(req)=>{return !!req.session.username;}, // 覆盖默认的登陆检查器
);
// 授权拦截器
const authorizationInterceptor=new AuthorizationInterceptor(
(req)=>{return req.session.roles;} // 覆盖默认的角色访问器
);
// 如果你认证/授权都需要的话:
const authInterceptor=new AuthInterceptor(
(req)=>{return !!req.session.username;}, // 覆盖默认的登陆检查器
(req)=>{return req.session.roles;} // 覆盖默认的角色访问器
);当前,还可以提供msg对象作为附加的默认返回消息(详见代码实现),但是大多情况下,不需要定制此参数。
异步式
除了上面演示的同步式的登陆检查器和角色访问器,还可以使用异步式进行定制:
// 支持各类异步方式:比如可以以Promise的方式进行检查
const authenticationInterceptor=new AuthenticationInterceptor(
// 覆盖默认的登陆检查器
(req)=>{
return new Promise(function(resolve,reject){
resolve(!!req.session.username);
});
}
);
// 支持各类异步方式:还可以以callback的方式进行检查
const authorizationInterceptor=new AuthorizationInterceptor(
// 覆盖默认的角色访问器
(req,callback)=>{
setTimeout(function() {
callback(null,req.session.rolelist);
}, 100);
}
);
const interceptor=new AuthInterceptor(
(req)=>{return !!req.session.username;},
(req)=>{
return new Promise(function(resolve,reject){
resolve(req.session.rolelist);
});
}
);除此之外,requireTrue()方法也支持使用异步式进行拦截:
const interceptor=new AuthorizationInterceptor();
interceptor.requireTrue(function(req){
return Promise.resolve(req.sth);
});如何拦截请求
AuthenticationInterceptor和AuthorizationInterceptor实例对请求的拦截是利用express中间件原理实现的。
拦截器实例对象有一系列requireXxx()方法,比如
requireLogin()requireRole()requireAnyRole()requireAllRoles()requireTrue()
AuthInterceptor的requireXxx()只是简单调用AuthenticationInterceptor和AuthorizationInterceptor的相应requireXxx()方法。
每个这种方法都是一个高阶函数,调用后会返回一个中间件函数,用于拦截请求:
// 要求拥有 "ROLE_ROOT" 角色,否则提示失败消息然后重定向到根目录"/"
router.use("/admin",interceptor.requireRole("ROLE_ROOT","/"));安装与测试
通过npm安装:
> npm install express-security --save测试:
> npm run test使用示例
可以根据需要,分别实例化一个AuthenticationInterceptor和AuthorizationInterceptor。
const express=require('express');
const {AuthInterceptor,AuthenticationInterceptor,AuthorizationInterceptor}=require('express-security');
const router=express.Router();
const authenInterceptor=new AuthencationInterceptor(
(req)=>{return !!req.session.username;},
);
const interceptor=new AuthorizationInterceptor(
(req)=>{return req.session.roles;}
);
// 要求登陆
router.use('/dashboard',authenInterceptor.requireLogin());
// 要求登陆,自定义重定向页面
router.use('/user/detail',authenInterceptor.requireLogin("/account"));
// 要求拥有 "ROLE_ADMIN" 角色
router.use("/admin",interceptor.requireRole("ROLE_ADMIN","/"));
// 要求拥有 "ROLE_ROOT"、"ROLE_ADMIN" 中任意一个角色
router.use("/sudo",interceptor.requireAnyRole(["ROLE_ROOT","ROLE_ADMIN"]));
// 要求拥有 "ROLE_0"、"ROLE_1"、"ROLE_2" 中全部角色
router.use("/holy",interceptor.requireAllRoles(["ROLE_0","ROLE_1","ROLE_2"]));
// 要求返回正确值的可调用对象
router.use("/shit",interceptor.requireTrue((req)=>{return !! req.query.sth;},"/"));如果同时需要根据用户登录状态和角色信息对请求进行拦截,也可以直接实例化一个AuthInterceptor作为统一的外部接口。
const AuthInterceptor=new AuthInterceptor(
(req)=>{return !!req.session.username;},
(req)=>{return req.session.roles;}
);案例
参见我的这篇笔记:ASP.NET 与 Node.js 的协作实践