NTAG215卡写入受保护数值与JWT的正确逻辑实现问询
NTAG215 存储可修改数值与只读JWT的正确实现方案
核心逻辑梳理
数值存储优化
不要用字符串存储金额,而是将十进制数值转换为整数(比如5432.50× 100 =543250),用4字节无符号整数存在单个页面(如页面4)。这样修改余额时直接操作整数,避免字符串解析的错误和开销,还能节省存储空间。JWT存储与只读锁定
NTAG215的用户可用页面范围是页面4到230(页面231及之后是密码、锁定控制等系统区域,不可用于数据存储)。JWT从页面5开始写入,按每页4字节分块处理,最后一页不足4字节时补0填充。写完JWT后,通过锁定命令将对应页面设置为只读,确保后续无法修改。认证与操作权限
只有密码认证成功后,才能修改数值页面;JWT页面锁定后,即使认证通过也无法修改,符合只读需求。
完善后的代码实现
import android.nfc.Tag import android.nfc.tech.MifareUltralight import android.util.Log import java.io.IOException import java.nio.ByteBuffer import java.nio.ByteOrder fun writeAndProtectTag(intent: Intent) { Thread { val tag = intent.getParcelableExtra<Tag>(NfcAdapter.EXTRA_TAG) ?: return@Thread var mifare: MifareUltralight? = null try { mifare = MifareUltralight.get(tag) mifare.connect() // 密码认证(PWD_AUTH命令0x1B) val pwd = "-_bA".toByteArray() val expectedPack = "cC".toByteArray() val authResponse = mifare.transceive(byteArrayOf(0x1B.toByte(), pwd[0], pwd[1], pwd[2], pwd[3])) if (authResponse?.size != 2 || authResponse[0] != expectedPack[0] || authResponse[1] != expectedPack[1]) { Log.d("NFC", "认证失败:PACK不匹配") return@Thread } // 1. 写入可修改的数值(示例:5432.50 → 转换为543250,用4字节无符号整数存储) val amount = 543250 // 代表5432.50 val amountBytes = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(amount).array() mifare.writePage(4, amountBytes) // 2. 写入JWT并锁定对应页面 val jwt = "这里替换为你的350字符左右的JWT字符串" val jwtBytes = jwt.encodeToByteArray() val startPage = 5 var currentPage = startPage // 分块写入JWT for (i in jwtBytes.indices step 4) { val pageData = ByteArray(4) System.arraycopy(jwtBytes, i, pageData, 0, minOf(4, jwtBytes.size - i)) mifare.writePage(currentPage++, pageData) } // 可选:锁定JWT所在页面(使其只读) // NTAG215的锁定控制页是页面231,每个字节控制8个页面的锁定状态 // 计算JWT占用的页面范围,设置对应锁定位(1表示锁定只读) // 示例:锁定页面5到页面X,需根据实际占用页面数计算锁定位 // lockBytes[0] 控制页面0-7,lockBytes[1]控制8-15,以此类推 // 修改后写入锁定页:mifare.writePage(lockPage, lockBytes) Log.d("NFC", "数据写入与保护完成") } catch (e: IOException) { Log.e("NFC", "IO异常:${e.message}", e) } catch (e: Exception) { Log.e("NFC", "未知异常:${e.message}", e) } finally { try { mifare?.close() } catch (e: IOException) { Log.e("NFC", "关闭标签失败:${e.message}", e) } } }.start() }
关键细节说明
- 数值存储:用
ByteBuffer将整数转换为4字节大端序字节数组,确保跨设备读取的一致性,修改余额时只需重新计算整数并写入页面4即可。 - JWT分块写入:通过循环按4字节分割JWT字节数组,不足4字节的页面自动补0,符合NTAG215每页4字节的写入要求。
- 页面锁定(可选):若需严格保证JWT只读,可修改页面231的锁定控制字节,将JWT所在页面的锁定位设为1(具体位映射需参考NTAG215官方手册),锁定后即使认证成功也无法修改这些页面。
- 错误处理:移除了无用的
while (!mifare.isConnected)循环,增加了日志输出,避免空指针异常。
内容的提问来源于stack exchange,提问作者Orlay Garcia Duconge
相关产品推荐
相关产品推荐

