后端十年经验彻底讲透什么时候用JWT Token,什么时候用签名(sign)机制?
什么时候用JWT Token什么时候用签名sign机制后端十年经验彻底讲透做后端开发这么多年面试和日常CRUD中被问得最多、也是新手最容易踩坑的问题接口鉴权到底用JWT还是Sign签名两者区别是什么什么场景该用谁能不能一起用很多初级开发者一直混淆两个机制简单认为都是“传一串字符串校验权限”随便拿来即用。这就导致线上频繁出现数据被篡改、接口被刷、用户身份伪造、权限越权等安全漏洞。直白说一句行业底层规则JWT 是用来「认人」身份认证Sign 签名是用来「认数据」完整性校验、防重放。本文结合十年后端开发经验搭配流程图 PHP完整可运行代码 场景对照表 避坑总结帮你彻底吃透两者的选型逻辑以后开发不用死记硬背直接按需套用。01 核心本质两者解决的完全不是一个问题1、JWT Token无状态身份认证JWTJSON Web Token核心定位用户登录身份凭证。传统Session需要服务端存储会话信息占用服务器内存无法适配分布式、前后端分离、小程序/APP场景。而JWT是无状态的服务端无需存储任何用户登录信息所有用户身份、过期时间、权限信息全部加密封装在Token字符串中由客户端本地存储。核心能力识别当前请求的用户是谁、是否登录、权限如何。短板致命问题JWT无法严格防篡改、无法防重放攻击单纯使用JWT极易导致接口被恶意刷请求、参数篡改。2、Sign签名机制数据安全校验接口Sign签名核心定位保证请求数据完整、真实、唯一。签名机制不记录用户登录状态、不识别用户身份。原理是将接口所有请求参数排序拼接配合密钥加密生成签名服务端接收参数后重复加密校验对比。核心能力防数据篡改、防恶意伪造请求、防接口重放、保障第三方对接安全。短板致命问题无法存储用户信息不能单独做登录态管理无法识别用户身份。02 工作流程对比流程图1、JWT 身份认证流程验证成功每次请求携带Token校验通过校验失败用户账号密码登录服务端校验账号密码生成JWT Token返回客户端客户端本地存储Token服务端解析校验签名判断过期识别用户身份,执行业务逻辑返回401未授权2、Sign 签名校验流程一致不一致客户端组装请求参数参数排序拼接密钥加密生成Sign请求携带参数Sign传给服务端服务端剔除Sign、参数排序、重新加密对比客户端Sign与服务端生成Sign数据合法,放行请求数据被篡改,拒绝请求03 PHP完整实战代码可直接生产复用1、PHP JWT 生成与校验工具类适配前后端分离登录鉴权支持自定义过期时间原生PHP实现无需扩展依赖。?phpclassJwtUtil{// 自定义密钥生产环境务必复杂且保密privateconstJWT_KEYbackend_jwt_2026_secret;// 加密算法privateconstALGHS256;/** * 生成JWT Token * param int $userId 用户ID * param int $expire 过期时间 秒 * return string */publicstaticfunctioncreateToken(int$userId,int$expire7200):string{// 头部信息$headerjson_encode([algself::ALG,typJWT]);// 载荷信息存放用户非敏感信息$payloadjson_encode([user_id$userId,iattime(),exptime()$expire]);// base64编码$base64Headerself::base64UrlEncode($header);$base64Payloadself::base64UrlEncode($payload);// 生成签名$signaturehash_hmac(self::ALG,$base64Header...$base64Payload,self::JWT_KEY,true);$base64Signself::base64UrlEncode($signature);return$base64Header...$base64Payload...$base64Sign;}/** * 校验JWT Token * param string $token * return array|false */publicstaticfunctionverifyToken(string$token){$tokenArrexplode(.,$token);if(count($tokenArr)!3){returnfalse;}[$header,$payload,$sign]$tokenArr;// 校验签名合法性$verifySignself::base64UrlEncode(hash_hmac(self::ALG,$header...$payload,self::JWT_KEY,true));if($verifySign!$sign){returnfalse;}// 校验过期时间$payloadDatajson_decode(self::base64UrlDecode($payload),true);if(empty($payloadData[exp])||$payloadData[exp]time()){returnfalse;}return$payloadData;}// 兼容JWT标准base64url编码privatestaticfunctionbase64UrlEncode(string$str):string{returnrtrim(strtr(base64_encode($str),/,-_),);}privatestaticfunctionbase64UrlDecode(string$str):string{returnbase64_decode(strtr($str,-_,/));}}// 测试生成Token$tokenJwtUtil::createToken(10086);echo生成JWT Token.$token.PHP_EOL;// 测试校验Tokenvar_dump(JwtUtil::verifyToken($token));?2、PHP Sign签名生成与校验工具类通用接口签名方案适配支付接口、第三方API、开放接口支持过滤空参数、自动排序。通用接口签名方案适配支付接口、第三方API、开放接口支持过滤空参数、自动排序。为解决接口重放攻击漏洞生产环境必须搭配**时间戳(timestamp) 随机字符串(nonce)**实现防重放以下是完整版防重放签名代码。?phpclassSignUtil{// 接口签名密钥privateconstSIGN_KEYbackend_sign_2026_secret;// 接口超时时间 单位秒默认1分钟防止重放攻击privateconstEXPIRE_TIME60;/** * 生成接口签名带防重放时间戳随机数 * param array $params 请求参数 * return array */publicstaticfunctionmakeSign(array$params):array{// 1. 加入防重放必备参数$params[timestamp]time();// 当前时间戳$params[nonce]self::getNonce();// 随机字符串// 2. 剔除空参数和自身sign字段unset($params[sign]);$paramsarray_filter($params,function($val){return$val!$val!null;});// 3. 按键名升序排序ksort($params);// 4. 键值对拼接$str;foreach($paramsas$key$value){$str.$key..$value.;}// 5. 拼接密钥并MD5加密$str.key.self::SIGN_KEY;$signstrtoupper(md5($str));// 返回完整请求参数含签名、时间戳、随机数return[sign$sign,timestamp$params[timestamp],nonce$params[nonce]];}/** * 校验签名 防重放校验 * param array $params * return bool */publicstaticfunctioncheckSign(array$params):bool{// 基础参数校验if(empty($params[sign])||empty($params[timestamp])||empty($params[nonce])){returnfalse;}// 1. 时间戳超时校验防止旧请求重复调用if(time()-$params[timestamp]self::EXPIRE_TIME){returnfalse;}// 2. 校验签名合法性$clientSign$params[sign];$serverSignself::makeSign($params)[sign];return$clientSign$serverSign;}/** * 生成唯一随机字符串 * return string */privatestaticfunctiongetNonce():string{returnmd5(uniqid(mt_rand(),true));}}// 测试参数$testParams[id1001,name测试订单,price99,sign];// 生成带防重放的签名参数$signDataSignUtil::makeSign($testParams);$requestParamsarray_merge($testParams,$signData);echo请求完整参数.json_encode($requestParams,JSON_UNESCAPED_UNICODE).PHP_EOL;// 校验签名与防重放var_dump(SignUtil::checkSign($requestParams));?3、JWTSign时间戳 双重校验完整接口实战生产最高安全方案前面我们单独实现了JWT登录鉴权、Sign防篡改防重放而企业资金、订单、用户核心资料等高危接口必须同时开启双重校验。整体校验顺序后端标准执行顺序不可颠倒1. 校验请求头JWT Token → 确认用户合法登录2. 校验接口Sign签名 时间戳/随机数 → 确认数据未篡改、非过期重放请求3. 全部校验通过执行业务逻辑下面模拟真实PHP接口完整实现整套闭环逻辑适配正式线上项目。?php// 引入上方封装好的工具类 JwtUtil、SignUtil/** * 高危业务接口订单创建接口 * 校验规则JWT身份认证 Sign签名校验 时间戳防重放 */classOrderController{// 模拟获取请求头TokenpublicstaticfunctiongetHeaderToken(){$headersgetallheaders();return$headers[Authorization]??;}// 订单创建接口入口publicstaticfunctioncreateOrder(){// 1. 获取请求参数$requestParams$_POST;// 2. JWT身份校验判断用户是否登录、身份是否合法$authTokenself::getHeaderToken();if(empty($authToken)){exit(json_encode([code401,msg未登录请先授权登录]));}// 解析用户信息$userInfoJwtUtil::verifyToken($authToken);if(!$userInfo){exit(json_encode([code401,msgToken失效或身份非法]));}$userId$userInfo[user_id];// 3. Sign时间戳随机数 防篡改、防重放校验if(!SignUtil::checkSign($requestParams)){exit(json_encode([code403,msg请求参数非法、已篡改或请求过期]));}// 4. 所有校验通过执行业务逻辑returnjson_encode([code200,msg订单创建成功,data[user_id$userId,order_snORD.date(YmdHis)]]);}}// 客户端模拟完整请求流程 // 1. 用户登录获取Token$tokenJwtUtil::createToken(10086);// 2. 组装订单请求参数生成带防重放的签名$postParams[goods_id6688,goods_name高端技术服务,amount199];$signDataSignUtil::makeSign($postParams);$requestDataarray_merge($postParams,$signData);// 3. 模拟接口请求// 模拟请求头 Authorization$_SERVER[HTTP_AUTHORIZATION]$token;// 模拟POST传参$_POST$requestData;// 调用接口echoOrderController::createOrder();?接口核心优势解析1、杜绝身份伪造依靠JWT严格校验用户登录身份未登录用户无法调用接口2、杜绝参数篡改黑客修改价格、商品ID等参数会直接导致Sign校验失败3、杜绝接口重放攻击依靠timestamp时效nonce唯一随机串过期请求、重复请求直接拦截4、完全符合互联网公司支付、订单、资金流接口的生产安全规范。04 精准选型场景对照表开发直接抄适用场景推荐方案核心原因前后端分离登录、APP/小程序登录、单点登录单独使用 JWT无状态、无需服务端存会话轻量化管理用户登录态支付接口、第三方开放API、对外合作接口单独使用 Sign 签名第三方无登录态只需保证数据不可篡改、请求合法用户敏感操作、订单提交、资金操作JWT Sign 双重校验JWT确认用户身份Sign防止参数篡改、重放刷接口内部后台普通查询接口仅JWT内部接口安全性要求低简化开发、提升效率公开查询、无需登录的业务接口仅Sign无用户身份仅拦截恶意请求和篡改参数05 后端必懂为什么高端场景必须两者混用很多新手疑惑既然JWT可以校验合法性为什么支付、订单、资金接口还要额外加Sign签名这里讲一个行业核心漏洞JWT一旦签发在过期时间内永久有效。如果用户Token泄露黑客可以复制Token修改接口请求参数调用敏感接口。JWT 只能验证“人是对的”无法验证“数据是对的”。而Sign签名刚好弥补短板每次请求参数变化签名都会变化哪怕Token被盗黑客修改参数后签名校验直接失败无法伪造请求。企业生产标准规范基础登录业务只用 JWT兼顾开发效率与体验高危、资金、对外业务JWT鉴权 Sign验参双重保障杜绝安全漏洞06 开发避坑总结面试高频考点1、JWT 负责身份认证解决「谁在请求」Sign 负责数据校验解决「数据是否合法」二者不可互相替代。2、JWT 载荷不要存放手机号、密码、银行卡等敏感数据JWT仅做Base64编码可直接解码查看并不加密。3、Sign 签名密钥绝对不能前端固化、泄露否则签名机制彻底失效。4、单点登录、移动端、前后端分离首选JWT第三方对接、开放接口、高危操作首选双校验方案。5、单纯JWT存在重放攻击风险高安全场景务必叠加Sign签名时间戳随机字符串三重校验彻底杜绝重放漏洞。6、签名防重放核心原理通过timestamp时效限制拦截过期请求通过nonce随机串保证单次请求唯一性二者结合黑客无法复用历史请求参数伪造接口请求。最后JWT和Sign不是二选一的对立方案而是互补的安全方案。作为后端开发不用死记硬背原理只需记住一句话要认人用JWT要认数据用Sign既要认人又要保数据安全两者一起用。看懂这篇文章以后开发接口鉴权、面试答题再也不会出错