下面是详细的 "node.js+captchapng+jsonwebtoken实现登录验证示例" 的攻略:
一、背景
在网站开发中,登录是非常普遍的需求。而如何确保用户登录的安全性,是需要我们考虑的重要问题之一。本文将介绍如何使用 node.js、captchapng 和 jsonwebtoken 模块,实现基于验证码和 token 的登录验证。
二、前置知识
在继续阅读本文之前,需要你掌握以下知识:
- node.js 环境的搭建和基础语法的学习;
- HTTP 请求和响应的基本概念;
- Express 框架的使用方法;
- 安装和使用 captchapng 和 jsonwebtoken 模块。
三、具体实现
1. 实现验证码
为了防止机器人暴力破解密码,我们需要在登录界面加入验证码。captchapng 模块可以帮助我们生成验证码图片。
首先,我们需要安装 captchapng 模块:
npm install captchapng
然后,在路由中添加生成验证码图片的代码:
const captchapng = require('captchapng');
const express = require('express');
const router = express.Router();
router.get('/captcha', (req, res) => {
const width = 80;
const height = 30;
const code = parseInt(Math.random() * 9000 + 1000);
const p = new captchapng(width, height, code);
p.color(0, 0, 0, 0); // 背景颜色
p.color(80, 80, 80, 255); // 文字颜色
const img = p.getBase64();
const imgbase64 = Buffer.from(img, 'base64');
res.writeHead(200, {
'Content-Type': 'image/png'
});
res.end(imgbase64);
});
以上代码中,我们定义了 /captcha
路由,用于生成验证码。代码中,我们首先定义了验证码的宽度和高度、验证码的内容(四位数字);然后,使用 captchapng 模块生成 png 格式的图片,并设置了背景颜色和文字颜色;最后,将生成的图片以 base64 格式返回到浏览器端。
2. 实现登录验证
接下来,我们需要使用 jsonwebtoken 模块来实现登录验证。Jsonwebtoken 是一个令牌(token)生成器和解析器,可以帮助我们生成并验证令牌。
先安装 jsonwebtoken 模块:
npm install jsonwebtoken
接着,在路由中添加验证用户名、密码和验证码的代码:
const jwt = require('jsonwebtoken');
const express = require('express');
const router = express.Router();
router.post('/login', async (req, res) => {
const { username, password, captcha } = req.body;
if (captcha !== req.session.captcha) {
res.status(400).json({ success: false, message: '验证码错误' });
return;
}
// 根据实际情况,需要从数据库或其它数据源中获取用户信息
const valid = username === 'admin' && password === '123456';
if (!valid) {
res.status(400).json({ success: false, message: '用户名或密码错误' });
return;
}
const token = jwt.sign({ username }, 'secret', { expiresIn: '1h' });
res.json({ success: true, token });
});
以上代码中,我们定义了 /login
路由,用于验证用户名、密码和验证码,并返回生成的 token。
在代码中,我们首先判断验证码是否正确,如果不正确,则返回错误提示;然后,根据实际情况,从数据库或其它数据源中获取用户信息,判断用户名和密码是否正确,如果不正确,则返回错误提示;最后,使用 jsonwebtoken 模块生成 token,并返回给浏览器端。
3. 实现 token 鉴权
登录验证完成后,我们需要在接下来的业务逻辑中,使用 token 进行鉴权。
const jwt = require('jsonwebtoken');
const express = require('express');
const router = express.Router();
router.get('/info', async (req, res) => {
try {
const token = req.headers.authorization.split(' ')[1];
const decoded = jwt.verify(token, 'secret');
const { username } = decoded;
// 根据实际情况,需要从数据库或其它数据源中获取用户信息
const user = { username, role: 'admin' };
res.json({ success: true, user });
} catch (e) {
res.status(401).json({ success: false, message: 'Token 鉴权失败' });
}
});
以上代码中,我们定义了 /info
路由,用于获取登录用户的信息。在代码中,我们首先从请求头中获取 token,然后使用 jsonwebtoken 模块对 token 进行鉴权,如果鉴权成功,则返回用户信息;否则,返回错误提示。
四、示例说明
为了更好地理解以上实现过程,我们将给出两个示例说明。
示例一:前后端分离应用
在前后端分离的应用中,前端和后端是分开部署的。前端发送请求到后端,后端返回 JSON 格式的数据,前端再进行处理和渲染。
以下是一个使用 Vue.js 和 Express 实现的前后端分离应用的示例:
前端首页代码:
<template>
<div>
<h1>我的网站</h1>
<p v-if="!loginUser">请登录</p>
<p v-if="loginUser">欢迎 {{ loginUser.username }}</p>
<button v-if="!loginUser" @click="showLoginDialog = true">登录</button>
<button v-if="loginUser" @click="logout">退出</button>
<div v-if="showLoginDialog">
<input type="text" v-model="username" placeholder="请输入用户名"/>
<input type="password" v-model="password" placeholder="请输入密码"/>
<input type="text" v-model="captcha" placeholder="请输入验证码"/>
<img :src="'/api/captcha?' + Math.random()" @click="refreshCaptcha" />
<button @click="login">登录</button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
loginUser: null,
showLoginDialog: false,
username: '',
password: '',
captcha: ''
}
},
methods: {
refreshCaptcha() {
this.$refs.captchaImg.src = '/api/captcha?' + Math.random();
},
async login() {
const { data } = await axios.post('/api/login', {
username: this.username,
password: this.password,
captcha: this.captcha
});
if (data.success) {
// 登录成功,将 token 存储到 localStorage 中
localStorage.setItem('token', data.token);
this.showLoginDialog = false;
this.fetchUserInfo();
} else {
alert(data.message)
}
},
async logout() {
localStorage.removeItem('token');
this.loginUser = null;
},
async fetchUserInfo() {
const token = localStorage.getItem('token');
if (token) {
try {
const { data } = await axios.get('/api/info', {
headers: { Authorization: 'Bearer ' + token }
});
this.loginUser = data.success ? data.user : null;
} catch (e) {
console.error(e);
}
}
}
},
mounted() {
this.fetchUserInfo();
}
}
</script>
后端代码:
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static('public'));
app.get('/api/captcha', (req, res) => {
// 生成验证码图片
});
app.post('/api/login', (req, res) => {
const { username, password, captcha }= req.body;
// 验证用户名、密码和验证码
// 生成 token 并返回
});
app.get('/api/info', (req, res) => {
const { authorization } = req.headers;
const token = authorization.split(' ')[1];
// 鉴权 token,返回用户信息
});
app.listen(3000, () => {
console.log('Server started on http://localhost:3000');
});
在以上示例中,我们定义了一个前端首页,在首页中实现了登录和注销功能。当用户登录成功后,将 token 存储到浏览器的 localStorage 中;在获取用户信息时,需要将存储在 localStorage 中的 token 从请求头中传递给服务器端。
示例二:基于 session 的应用
session 是另外一种实现用户登录验证的方式。以下是一个基于 session 实现的应用的示例。
前端代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>我的网站</title>
</head>
<body>
<h1>我的网站</h1>
<div>
<p v-if="!loginUser">请登录</p>
<p v-if="loginUser">欢迎 {{ loginUser.username }}</p>
<button v-if="!loginUser" @click="showLoginDialog = true">登录</button>
<button v-if="loginUser" @click="logout">退出</button>
<div v-if="showLoginDialog">
<input type="text" v-model="username" placeholder="请输入用户名"/>
<input type="password" v-model="password" placeholder="请输入密码"/>
<input type="text" v-model="captcha" placeholder="请输入验证码"/>
<img :src="'/captcha?' + Math.random()" @click="refreshCaptcha" />
<button @click="login">登录</button>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
new Vue({
el: 'body',
data: {
loginUser: null,
showLoginDialog: false,
username: '',
password: '',
captcha: ''
},
methods: {
refreshCaptcha() {
this.$refs.captchaImg.src = '/captcha?' + Math.random();
},
async login() {
const { data } = await axios.post('/login', {
username: this.username,
password: this.password,
captcha: this.captcha
});
if (data.success) {
// 登录成功,显示欢迎信息和注销按钮
this.showLoginDialog = false;
this.fetchUserInfo();
} else {
alert(data.message)
}
},
async logout() {
await axios.post('/logout');
this.loginUser = null;
},
async fetchUserInfo() {
const { data } = await axios.get('/user');
if (data.success) {
this.loginUser = data.user;
}
}
},
async mounted() {
this.fetchUserInfo();
}
})
</script>
</body>
</html>
后端代码:
const express = require('express');
const session = require('express-session');
const app = express();
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: { secure: false }
}));
app.get('/captcha', (req, res) => {
// 生成验证码图片
});
app.post('/login', (req, res) => {
const { username, password, captcha }= req.body;
// 验证用户名、密码和验证码
// 将用户信息存入 session 中
});
app.get('/user', (req, res) => {
const { user } = req.session;
if (!user) {
res.json({ success: false, message: '请先登录' });
} else {
res.json({ success: true, user });
}
});
app.post('/logout', (req, res) => {
// 销毁 session
});
app.listen(3000, () => {
console.log('Server started on http://localhost:3000');
});
在以上示例中,我们利用了 Express 的 session 中间件,来存储用户信息。具体地,当用户登录成功时,我们将用户信息存入 session 中;当获取用户信息时,我们从 session 中读取用户信息。当用户注销时,我们销毁 session。
五、结语
本文详细讲解了如何使用 node.js、captchapng 和 jsonwebtoken 模块,实现基于验证码和 token 的登录验证。示例代码同时也给出了如何在前后端分离应用和基于 session 的应用中,实现登录验证的方法。希望这篇文章能够对您有所帮助。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:node.js+captchapng+jsonwebtoken实现登录验证示例 - Python技术站