全面鉴权
这一节我们来介绍一下 Passport.js,这是一个强大的 NodeJS 的认证中间件
Passport.js 提供了多种认证方式,账号密码、OpenID、ApiKey、JWT、OAuth、三方登录等等。
使用 Passport.js 认证要配置三个部分:
- 认证策略
- 中间件
- 会话
接下来我们以 账号密码 认证为例,来演示一下 Passport.js 的使用
准备工作
新建一个基础的 evp-express 项目
安装依赖
- 安装 passport.js
npm install passport
- 安装 local 策略
npm install passport-local
创建页面
在 public 目录下面创建 index.html
, fail.html
, home.html
3个页面:
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="/login" method="post">
<input name="username" placeholder="username..." />
<input name="password" placeholder="password..." />
<button type="submit">Login</button>
</form>
</body>
</html>
fail.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fail</title>
</head>
<body>
<h1>Fail</h1>
<a title="gologin" href="/views">Go login</a>
</body>
</html>
home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home</title>
</head>
<body>
<h1>Hello, Home!</h1>
</body>
</html>
设置静态目录
app.js:
const config = require('./config.js').get();
//...
app.use('/views', express.static(config.public, { extensions: ['html'] }));
这个 extensions 选项用于允许访问静态页面不带 html 后缀。
开启Session
app.js:
//...
app.use(session({
secret: 'secret',
resave: false,
saveUninitialized: true
}));
初始化passport
app.js:
const passport = require('passport');
//...
app.use(passport.initialize());
app.use(passport.session());
设置认证
步骤:
- 使用策略,规定认证过程,done是回调函数,可以接收三个参数:
- 异常
- 在会话中保存的用户信息,填 false 代表认证失败
- 其余数据,比如传递信息
- 序列化用户信息
- 反序列化用户信息
app.js:
const LocalStrategy = require('passport-local').Strategy;
//...
passport.use(new LocalStrategy(
function verify(username, password, done) {
if (username == 'root' && password == 'root') {
return done(null, { username, password});
}
return done(null, false, {message: "None"});
}
))
passport.serializeUser((user, cb) =>{
process.nextTick(()=>{
cb(null, {username: user.username, password: user.password})
})
})
passport.deserializeUser((user, cb) => {
process.nextTick(()=>{
return cb(null, user);
});
});
编写登录接口
router/index.js:
const { Json, Form, Multi, FromPlus } = require('../midwares/bodyParser');
//...
router.post('/login', FromPlus, passport.authenticate('local', {
failureRedirect: '/views/fail',
failureFlash: false
}), (req, res, next) => {
res.redirect('/views/home');
});
前端页面在表单中填写登录信息,先按照表单格式解析一下,然后再加入 passport 的认证中间件,指定策略为 local
, 并指定认证失败跳转到 fail.html
,成功则重定向到 homte.html
,这个可以和失败重定向一样,作为 successRedirect
选项写到上面。
保护接口
编写一个判断时候登录的中间件函数:
function isLogined(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/views/');
}
对 /
路由进行登录保护:
router.get('/', isLogined, (req, res, next) => {
logger.info('Hello World!');
res.json(Resp.ok('Hello World!', 1, null));
});
测试
此时运行项目,在浏览器中访问http://127.0.0.1:8080,会被重定向到登录界面,登录成功后在地址栏可以正常访问到这个被保护的路由,登录失败则会被重定向到 fail 页面。
Passport.js 的更多用法请自行探索,详见官方文档:https://www.passportjs.org/docs/