在小程序开发中,建立一套安全且高效的身份认证体系是所有业务逻辑的基石。本文将深度解析一套成熟的“前端凭证获取 + 后端身份映射 + 令牌(Token)持久化”的全栈方案。
一、 系统架构与配置分离
为了保证代码的可维护性,首先需实现全局配置的解耦。在 config.js 中定义核心参数,避免硬编码:
// config.js - 全局环境配置
var DOMAIN = "api.your-domain.com"; // 生产环境 API 域名
var PAGECOUNT = '10'; // 分页步长
export default {
getDomain: DOMAIN,
getPageCount: PAGECOUNT,
// 屏蔽具体业务版本号与私有配置
}
二、 客户端层:身份凭证获取流
小程序端的认证逻辑集中于 Auth.js。其核心是通过 Promise 封装异步调用,处理微信原生的 code 获取与用户信息上报。
1. 临时授权码(js_code)获取
wx.login 是认证的起点,获取到的 code 是后续换取用户唯一标识(OpenID)的必要凭证。
// Auth.js - 封装静默登录
Auth.wxLogin = function() {
return new Promise(function (resolve, reject) {
wx.login({
success: function (res) {
let args = {};
args.js_code = res.code; // 获取临时凭证
resolve(args);
},
fail: function (err) {
reject(err);
}
});
})
}
2. 用户上下文获取与上报
利用 wx.getUserProfile 获取非敏感元数据(昵称、头像),并触发后端认证接口。
// Auth.js - 处理用户显式授权逻辑
Auth.agreeGetUser = function(e, wxLoginInfo, authFlag) {
return new Promise(function(resolve, reject) {
let args = { js_code: wxLoginInfo.js_code };
wx.getUserProfile({
lang: 'zh_CN',
desc: '用于完善会员资料',
success: (res) => {
let userInfo = res.userInfo;
args.avatarUrl = userInfo.avatarUrl;
args.nickname = userInfo.nickName;
// 调用后端 API 执行身份交换
var url = Api.getOpenidUrl();
var postOpenidRequest = wxRequest.postRequest(url, args);
postOpenidRequest.then(response => {
if (response.data.status == '200') {
// 登录成功,执行状态持久化
resolve(response.data);
}
})
}
});
});
}
三、 服务端层:身份交换与账号映射逻辑
后端通过 REST API 接收客户端上报的 js_code,通过微信官方接口 jscode2session 完成从“微信用户”到“系统会员”的转换。
1. 路由注册与环境初始化
后端需确保跨域安全与环境兼容性,尤其针对 PHP 8.0+ 的 Session 策略进行防御性处理。
// User_Controller.php - REST 接口注册
public function register_routes() {
register_rest_route($this->namespace, '/' . $this->module . '/login2', [
'methods' => 'POST',
'callback' => [$this, 'user_login2'],
'permission_callback' => '__return_true', // 允许公开访问鉴权接口
]);
}
2. 身份映射与 Token 签发
这是鉴权逻辑的核心。后端在获取 openid 后,需执行“存在即更新,不存在即创建”的幂等操作。
// User_Controller.php - 核心登录处理逻辑
public function user_login2($request) {
$code = $this->param_value($request, 'code', '');
$nickname = $this->param_value($request, 'nickName', '');
// 1. 请求微信服务器换取 OpenID
$params = [
'appid' => $app_id, // 后端安全存储
'secret' => $app_secret, // 后端安全存储
'js_code' => $code,
'grant_type' => 'authorization_code'
];
$result = wp_remote_get(add_query_arg($params, 'https://api.weixin.qq.com/sns/jscode2session'));
$wx_session = json_decode($result['body'], true);
$openid = $wx_session['openid'] ?? '';
// 2. 账号映射逻辑
$user = get_user_by('login', $openid);
if ($user) {
$user_id = $user->ID;
wp_update_user(['ID' => $user_id, 'display_name' => $nickname]);
} else {
$user_id = wp_insert_user([
'user_login' => $openid, // 唯一标识作为用户名
'role' => 'subscriber',
'user_pass' => wp_generate_password(16, false),
]);
}
// 3. 生成并持久化业务 Token
$token = md5(uniqid($openid, true));
update_user_meta($user_id, 'custom_auth_token', $token);
return $this->make_success([
"nickname" => $nickname,
"token" => $token, // 返回给前端的唯一授权令牌
]);
}
四、 业务授权流:基于 Token 的权限校验
在完成认证后,后续所有的业务请求(如点赞、收藏)均需携带 token 进行状态识别。
| 流程 | 逻辑实现 | 核心代码引用 |
| 客户端携带 | 从本地缓存读取并放入请求 Payload | wx.getStorageSync('token') |
| 服务端识别 | 通过 Meta 检索反查用户 ID | get_user_id_by_token($token) |
| 数据操作 | 校验通过后执行数据库事务 | $wpdb->insert(...) |
// User_Controller.php - 点赞业务权限校验
public function user_like($request) {
global $wpdb;
$token = $this->param_value($request, 'token', '');
// 校验 Token 有效性,获取 UserID
$user_id = $wpdb->get_var($wpdb->prepare(
"SELECT user_id FROM $wpdb->usermeta WHERE meta_key='custom_auth_token' AND meta_value=%s LIMIT 1",
$token
));
if (!$user_id) {
return $this->make_error('Invalid Token');
}
// 执行业务逻辑...
}
五、 总结与安全建议
本方案实现了 Stateless(无状态) 的会话管理模式,其优势在于:
-
解耦性:小程序前端不涉及任何敏感密钥(Secret),仅通过
code与服务端通信。 -
持久化:利用
wx.setStorageSync与服务端user_meta的映射,实现了用户在跨会话(Session)后的状态自动找回。 -
安全性:业务流程中使用随机
token代替openid传输,显著降低了用户唯一标识被嗅探的风险。


看不懂,但是感觉很厉害👍🏻
哈哈