需求
假如一个详情页的地址栏有一个商品id,但是又不想用户通过更改id来看其他商品详情。
方案设计
- 在商品列表页获取列表数据时提供活动id对应的签名,活动id和签名一一对应,生成签名使用md 如sign=MD5(
id${id}sk${secretKey}
),secretKey是密钥; - 在跳转至详情页时将签名带上,如:details?id=123&sign=xxx;
- 在请求活动详情时带上id和sign(签名);
- node层通过id和密钥重新生成签名,重新生成的签名和请求接口时的签名对比,如果一致则表示活动id没有被篡改。
代码实现(部分)
// 判断id是否修改中间件
import { Context } from "koa";
import { KoaMiddlewareInterface, Middleware } from "routing-controllers";
import * as MD5 from 'md5'
import getApolloConfig from '@xxx/apollo'; // 引入阿波罗配置
@Middleware({ type: "before" })
export default class IdCheckMiddleware implements KoaMiddlewareInterface {
async use(context: Context, next: (err?: any) => Promise<any>,): Promise<any> {
const config = getApolloConfig()
// 是否严格模式下的id(是否需要校验id签名) '0'不需要 '1'需要
const strictId = config['strictId']
// 这样可以通过阿波罗配置来即时控制是否需要校验签名
if (strictId === '0') {
return next()
}
// 生成md5签名的密钥
const secretKey = config['idSecretKey']
// id和sign通过header传过来(其他传参方法也一样)
const id = context.request.header["id"] || ''
// 再次生成签名
const nodeSign = MD5(`id${id}sk${secretKey}`)
// 客户端传来的签名
const sign = context.request.header["sign"] || ''
if (nodeSign !== sign) {
context.body = {
code: 3,
error: ['非法的id'],
};
} else {
return next()
}
}
}