以下是克隆本教程中使用的应用程序源代码的命令
git clone --branch v1.2.0 https://github.com/redis-developer/mobile-banking-solutions
用户成功输入其登录凭据后,移动银行应用程序会使用服务器创建的 token
和 sessionId
来代表用户的身份。该 token
存储在 Redis 中,持续用户会话期间,并发送到银行应用程序客户端(移动/浏览器)的登录响应中。然后,客户端应用程序在每次向服务器发出请求时发送 token
,服务器在处理请求之前验证该 token
。
Redis Stack 支持 JSON 数据类型,并允许您索引和查询 JSON 以及 更多。因此,您的会话存储不仅限于简单的键值字符串化数据。
会话存储存储与每个用户在其会话期间浏览应用程序相关的关键信息。移动银行会话数据可能包括但不限于以下信息
user
, admin
, supervisor
, super-admin
等。express-session
和 connect-redis-stack
库的集成)阅读我们的电子书,它回答了以下问题: JSON Web 令牌 (JWT) 安全吗? 它讨论了何时以及如何安全地使用 JWT,并提供了经过实战检验的会话管理解决方案。
以下是克隆本教程中使用的应用程序源代码的命令
git clone --branch v1.2.0 https://github.com/redis-developer/mobile-banking-solutions
下载上面的源代码,并运行以下命令以启动演示应用程序
docker compose up
docker up 并运行后,在浏览器中打开 https://localhost:8080/ 网址以查看应用程序
该应用程序利用了 Redis 核心数据结构、JSON、TimeSeries、搜索和查询功能。播种的数据后来用于显示可搜索的交易概述(实时更新),以及个人理财管理概述(实时余额和最大支出者更新)。
在应用程序启动时,在 app/server.js
中,会安排一个 cron 定期创建随机银行交易,并将这些交易播种到 Redis 中。
//cron job to trigger createBankTransaction() at regular intervals
cron.schedule('*/10 * * * * *', async () => {
const userName = process.env.REDIS_USERNAME;
createBankTransaction(userName);
//...
});
balanceAfter
值将记录在具有 balance_ts
键的 TimeSeries 中,用于每次交易。bigspenders
中,与之关联的 fromAccountName
成员将根据交易金额递增。请注意,此金额可以是正数或负数。let balance = 100000.0;
const BALANCE_TS = 'balance_ts';
const SORTED_SET_KEY = 'bigspenders';
export const createBankTransaction = async () => {
//to create random bank transaction
let vendorsList = source.source; //app/transactions/transaction_sources.js
const random = Math.floor(Math.random() * 9999999999);
const vendor = vendorsList[random % vendorsList.length]; //random vendor from the list
const amount = createTransactionAmount(vendor.fromAccountName, random);
const transaction = {
id: random * random,
fromAccount: Math.floor((random / 2) * 3).toString(),
fromAccountName: vendor.fromAccountName,
toAccount: '1580783161',
toAccountName: 'bob',
amount: amount,
description: vendor.description,
transactionDate: new Date(),
transactionType: vendor.type,
balanceAfter: balance,
};
//redis json feature
const bankTransaction = await bankTransactionRepository.save(transaction);
console.log('Created bankTransaction!');
// ...
};
const createTransactionAmount = (vendor, random) => {
let amount = createAmount(); //random amount
balance += amount;
balance = parseFloat(balance.toFixed(2));
//redis time series feature
redis.ts.add(BALANCE_TS, '*', balance, { DUPLICATE_POLICY: 'first' });
//redis sorted set as secondary index
redis.zIncrBy(SORTED_SET_KEY, amount * -1, vendor);
return amount;
};
使用 RedisInsight 查看示例 bankTransaction 数据
下载 RedisInsight 以查看您的 Redis 数据或在工作台中使用原始 Redis 命令。
Redis 集成到许多会话管理库中,我们将使用 connect-redis-stack 库作为本演示的示例,它为您的 express-session 应用程序提供 Redis 会话存储。
以下代码说明了使用 express-session
配置 Redis 会话。
import session from 'express-session';
import { RedisStackStore } from 'connect-redis-stack';
/* configure your session store */
const store = new RedisStackStore({
client: redis, //redis client
prefix: 'redisBank:', //redis key prefix
ttlInSeconds: 3600, //session expiry time
});
const app = express();
// ...
app.use(
session({
store: store, //using redis store for session
resave: false,
saveUninitialized: false,
secret: '5UP3r 53Cr37', //from env file
}),
);
//...
app.listen(8080, () => console.log('Listening on port 8080'));
让我们看看 /perform_login
API 代码,该代码在从 登录页面单击登录按钮时触发。
由于 connect-redis-stack 是一个 Express 中间件,因此会在请求开始时自动创建会话,并在 HTTP(API) 响应结束时更新,如果 req.session
变量被修改。
app.post('/perform_login', (req, res) => {
let session = req.session;
console.log(session);
/*
Session {
cookie: { path: '/', _expires: null, originalMaxAge: null, httpOnly: true }
}
*/
//hardcoded user for demo
if (req.body.username == 'bob' && req.body.password == 'foobared') {
//on successful login (for bob user)
session = req.session;
session.userid = req.body.username; //create session data
res.redirect('/index.html');
} else {
res.redirect('/auth-login.html');
}
});
在上面的代码中 - session.userid
变量在成功登录(对于“bob”用户)时被分配一个值,因此会在 Redis 中创建一个会话,分配数据,并且只将 Redis 键(sessionId)存储在客户端 cookie 中。
connect.sid
(只包含 sessionId)现在,对于来自客户端的每个其他 API 请求, connect-redis-stack 库会确保根据客户端 cookie(sessionId)从 Redis 加载会话详细信息到 req.session
变量。
考虑以下 /transaction/balance
API 代码来演示会话存储。
我们必须修改 req.session
变量以更新会话数据。让我们添加更多会话数据,例如用户的当前余额金额。
/* fetch all transactions up to an hour ago /transaction/balance */
transactionRouter.get('/balance', async (req, res) => {
const balance = await redis.ts.range(
BALANCE_TS,
Date.now() - 1000 * 60 * 5,
Date.now(),
);
let balancePayload = balance.map((entry) => {
return {
x: entry.timestamp,
y: entry.value,
};
});
let session = req.session;
if (session.userid && balancePayload.length) {
//adding latest BalanceAmount to session
session.currentBalanceAmount = balancePayload[balancePayload.length - 1]; //updating session data
}
res.send(balancePayload);
});
currentBalanceAmount
字段(“x”表示时间戳,“y”表示该时间戳的余额金额)希望本教程能帮助您了解如何使用 Redis 进行更好的会话管理,特别是在移动银行领域。有关该主题的更多资源,请查看下面的链接。