Express.js处理身份认证

分享于 

9分钟阅读

Javascript

  繁體

介绍

在本文中,制作一个简单的应用程序来演示如何在Express.js中处理身份验证。

项目设置

首先,创建一个名为simple-web-app的新文件夹,使用终端,导航到该文件夹,并创建一个框架Node.js项目:

 
$ npm init

现在,我们也可以安装Express:


$ npm install --save express

继续安装express-handlebars


$ npm install --save express-handlebars

我们还将使用另外两个Express中间件包(body-parsercookie-parser)来解析HTTP请求主体,并解析所需的Cookies以进行身份验证:


$ npm install --save body-parser cookie-parser

实现

我们要构建的应用程序将包含一个只有登录用户才能访问的"受保护"页面,否则,他们被重定向到主页-提示他们登录或注册。

首先,导入我们之前安装的库:


const express = require('express');
const exphbs = require('express-handlebars');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');

使用node的原生crypto模块进行密码哈希,并生成验证令牌-本文稍后将详细介绍。

接下来,创建一个简单的Express应用程序,并配置我们导入的中间件,以及Handlebars引擎:


const app = express();

// To support URL-encoded bodies
app.use(bodyParser.urlencoded({ extended: true }));

// To parse cookies from the HTTP Request
app.use(cookieParser());

app.engine('hbs', exphbs({
 extname: '.hbs'
}));

app.set('view engine', 'hbs');

// Our requests hadlers will be implemented here...

app.listen(3000);

默认情况下,在Handlebars中,模板扩展应该是.handlebars,现在创建几个模板文件:

layouts文件夹在view文件夹中将保存你的主布局,这将为其他模板提供基本的HTML。

创建main.hbs,主包装页面:




 
 
 
 
 Document

 
 
 

 


 {{{body}}}
 

其他模板将呈现此模板的内部{{{body}}}标记,我们在这个布局中导入了HTML样板文件以及Bootstrap所需的CSS和JS文件。

完成主包装之后,创建home.hbs页面,提示用户登录或注册:



 Simple Authentication App





 Login
 Register

然后,创建一个指向路径root path (/ )的请求处理程序来呈现主模板。


app.get('/', function (req, res) {
 res.render('home');
});

启动应用程序,并导航到http://localhost:3000

帐户注册

有关帐户的信息通过registration.hbs页面收集:



 



 {{#if message}}
 


 {{message}}
 
{{/if}}First NameLast NameEmail addressPasswordConfirm PasswordLogin

密码和确认密码并将操作设置为/register route,

创建一个请求句柄,以便在用户访问http://localhost:3000/register时呈现注册模板:


app.get('/register', (req, res) => {
 res.render('register');
});


const crypto = require('crypto');

const getHashedPassword = (password) => {
 const sha256 = crypto.createHash('sha256');
 const hash = sha256.update(password).digest('base64');
 return hash;
}

当用户提交注册表单时,POST请求被发送到/register路径。

由于每个服务器重新启动都将重新初始化数组,因此硬编码一个用户,以便测试每次初始化:


const users = [
 // This user is added to the array to avoid creating a new user on each restart
 {
 firstName: 'John',
 lastName: 'Doe',
 email: '[email protected]',
 // This is the SHA256 hash for value of `password`
 password: 'XohImNooBHFR0OVvjcYpJ3NgPQ1qq73WKhHvch0VQtg='
 }
];

app.post('/register', (req, res) => {
 const { email, firstName, lastName, password, confirmPassword } = req.body;

 // Check if the password and confirm password fields match
 if (password === confirmPassword) {

 // Check if user with the same email is also registered
 if (users.find(user => user.email === email)) {

 res.render('register', {
 message: 'User already registered.',
 messageClass: 'alert-danger'
 });

 return;
 }

 const hashedPassword = getHashedPassword(password);

 // Store user into the database if you are using one
 users.push({
 firstName,
 lastName,
 email,
 password: hashedPassword
 });

 res.render('login', {
 message: 'Registration Complete. Please login to continue.',
 messageClass: 'alert-success'
 });
 } else {
 res.render('register', {
 message: 'Password does not match.',
 messageClass: 'alert-danger'
 });
 }
});

已接收的emailfirstNamelastNamepassword和密码已验证过。

如果每个验证都成功,我们对密码进行散列,并将信息存储在数组内部,并将用户重定向到登录页面,否则,用错误消息重新呈现注册页面。

现在,访问/register端点以验证它是否正常工作:

登录帐号

通过注销,我们可以实现登录功能,首先创建login.hbs页面:



 



 {{#if message}}
 


 {{message}}
 
{{/if}}Email addressPasswordLogin

然后,为该请求创建一个处理程序:


app.get('/login', (req, res) => {
 res.render('login');
});

当用户提交表单时,此表单将向POST请求发送到/login,不过,我们要做的另一件事是为登录发送身份验证令牌,此令牌将用于标识用户,每次发送HTTP请求时,此令牌将作为cookie发送:


const generateAuthToken = () => {
 return crypto.randomBytes(30).toString('hex');
}

使用helper方法,我们可以为登录页面创建一个请求处理程序:


// This will hold the users and authToken related to users
const authTokens = {};

app.post('/login', (req, res) => {
 const { email, password } = req.body;
 const hashedPassword = getHashedPassword(password);

 const user = users.find(u => {
 return u.email === email && hashedPassword === u.password
 });

 if (user) {
 const authToken = generateAuthToken();

 // Store authentication token
 authTokens[authToken] = user;

 // Setting the auth token in cookies
 res.cookie('AuthToken', authToken);

 // Redirect user to the protected page
 res.redirect('/protected');
 } else {
 res.render('login', {
 message: 'Invalid username or password',
 messageClass: 'alert-danger'
 });
 }
});

击中/login端点,会看到:


EXP  auth  expr  Express  
相关文章