dromara/Sa-Token · warning · RuntimeException
设备id或用户id不能为空
Error message
设备id或用户id不能为空
What it means
Demo utility in sa-token-demo-device-lock (device-binding example). setDeviceIdToUserId persists a deviceId -> userId mapping with a 1200-second TTL and requires both arguments to be non-empty; an empty deviceId (or the always-non-empty long check failing on userId==0, since SaFoxUtil.isEmpty(long) boxes to Long and only 0/empty triggers) throws RuntimeException. It is sample code, not part of the library.
Source
Thrown at sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/util/DeviceLockCheckUtil.java:20
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* 设备锁操作工具类
* @author click33
* @since 2025/3/5
*/
public class DeviceLockCheckUtil {
/**
* 保存设备id与用户id的映射关系
* @param deviceId /
* @param userId /
*/
public static void setDeviceIdToUserId(String deviceId, long userId) {
if(SaFoxUtil.isEmpty(deviceId) || SaFoxUtil.isEmpty(userId)) {
throw new RuntimeException("设备id或用户id不能为空");
}
SaManager.getSaTokenDao().set(saveKeyPrefix() + deviceId, String.valueOf(userId), 1200);
}
/**
* 返回设备id绑定的用户id
* @param deviceId /
*/
public static long getUserIdByDeviceId(String deviceId) {
String userIdStr = SaManager.getSaTokenDao().get(saveKeyPrefix() + deviceId);
if(userIdStr == null) {
throw new RuntimeException("此设备id目前未绑定任何用户");
}
return Long.parseLong(userIdStr);
}
// 返回数据保存时使用的前缀
public static Object saveKeyPrefix() {View on GitHub (pinned to ac2c7f6e94)
Solutions
- Ensure the client submits a non-empty deviceId (usually a header set by the app/mini-program) before calling setDeviceIdToUserId
- Guard the call: if (SaFoxUtil.isEmpty(deviceId) || userId <= 0) return error to the caller instead of throwing
- If you adapted this code, change SaFoxUtil.isEmpty(userId) to userId <= 0 so legitimate id 0 is not rejected
Example fix
// before
DeviceLockCheckUtil.setDeviceIdToUserId(requestDeviceId, userId); // null device id
// after
if (SaFoxUtil.isEmpty(requestDeviceId) || userId <= 0) {
throw new SaTokenException("请提交有效的设备id与用户id");
}
DeviceLockCheckUtil.setDeviceIdToUserId(requestDeviceId, userId); Defensive patterns
Strategy: validation
Validate before calling
if (SaFoxUtil.isEmpty(deviceId) || userId <= 0) {
// return a 400 to the client; do not call setDeviceIdToUserId
} Type guard
public static boolean isValidDeviceBinding(String deviceId, long userId) {
return deviceId != null && !deviceId.trim().isEmpty() && userId > 0;
} Prevention
- Require the client to send a device id (header) before binding
- If you adapt this demo, replace SaFoxUtil.isEmpty(userId) with userId <= 0
- Validate at the controller boundary, not inside the DAO util
When it happens
Trigger: Calling DeviceLockCheckUtil.setDeviceIdToUserId(deviceId, userId) with deviceId null/empty/whitespace, or userId == 0 (SaFoxUtil.isEmpty treats boxed 0 as empty).
Common situations: Frontend not sending the device-id header/param so the controller passes null; using userId 0 as a sentinel; adapting the demo and keeping the isEmpty(long) guard which wrongly rejects id 0.
Related errors
AI-assisted analysis of dromara/Sa-Token@ac2c7f6e94 (2026-08-14).
Data as JSON: /api/errors/9a5c72bd172d4169.
Report an issue: GitHub.