在现代网络应用中,经常会遇到需要身份核实的场景,身份证核验是常见的一种方式。
身份证号码的核验不仅涉及到前端的用户体验,也是后端数据准确性的重要保障。
本文将从前端开发者的视角,介绍中国身份证号码的基本规则以及如何在前端实现身份证号码的校验。
另外,规则校验不能作为身份证号码的真实性校验,需要通过合法可信的数据源进行核验,例如公安数据源。
身份证号码的基本规则
中国的身份证号码由 18 位数字组成,其中前 6 位是地址码,接下来的 8 位是出生日期码,再接下来的 3 位是顺序码,最后一位是校验码(check number)。 前 17 位又叫本体码(master number)。
地址码
地址码是出生地的行政区划代码,这个代码可以在国家标准 GBT-2260 文档上找到。 这个代码不会随后续户籍地改变而改变,所以迁户口到外地,身份证号码是不会变的。
出生日期码
出生当天的日期,例如,某人 2024 年 9 月 1 日出生,其出生码为 20240901。
顺序码
同一出生地内,也就是地址码范围内,同年同月同日出生人的编订顺序号。奇数分配给男性,偶数分配给女性。
校验码
根据前 17 位本体码按照特定规则计算得出,用于检验身份证号码的正确性。 也就是说本体码前 17 位数字中任意一位发生变化,后面的校验码就会改变。 这也是为什么游戏防沉迷系统认证的时候,只把身份证号码的出生年月调大依旧没办法通过校验的原因。
校验码生成方式
- 将身份证号码的前 17 位本体码分别乘以不同的系数。
系数从第一位到第十七位依次为:7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2。
-
将这 17 位数字和系数相乘的结果相加。
-
将相加的结果除以 11,得到余数。
-
根据余数,通过查表得到对应的校验码,对应关系如下:
余数 | 校验码 |
---|---|
0 | 1 |
1 | 0 |
2 | X |
3 | 9 |
4 | 8 |
5 | 7 |
6 | 6 |
7 | 5 |
8 | 4 |
9 | 3 |
10 | 2 |
根据本体码生成校验码的代码实现:
/**
* 获取加权因子
*/
const getPosWeight: () => number[] = () => [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
/**
* 获取校验码
*/
const getCheckNumberArr: () => string[] = () => [
'1',
'0',
'X',
'9',
'8',
'7',
'6',
'5',
'4',
'3',
'2',
];
/**
* 根据本体码计算出校验码
* @param masterNumber 本体码
* @returns
*/
function calcCheckNumber(masterNumber: string) {
const masterNumArr = masterNumber.split('');
const masterWeightSum = getPosWeight().reduce((prev, current, i) => {
return (prev += parseInt(masterNumArr[i], 10) * current);
}, 0);
return getCheckNumberArr()[masterWeightSum % 11];
}
校验思路
地址码校验
将地址码放进数组,判断是否是合法地址码:
const addressCodes = [
'110101',
// ...
];
function isValidateAddressCode(addressCode: string) {
return addressCodes.includes(addressCode);
}
出生日期码校验
校验出生日期码是否是合法日期:
function isValidDate(dateStr: string) {
// 正则表达式,匹配格式为YYYYMMDD的日期字符串
const regex = /^\d{8}$/;
// 首先检查格式是否正确
if (!regex.test(dateStr)) {
return false;
}
// 将字符串分割成日期组成部分
const year = parseInt(dateStr.substring(0, 4), 10);
const month = parseInt(dateStr.substring(4, 6), 10) - 1; // JavaScript中月份是从0开始的
const day = parseInt(dateStr.substring(6, 8), 10);
// 使用Date对象来检查日期是否有效
const date = new Date(year, month, day);
return (
date.getFullYear() === year &&
date.getMonth() === month &&
date.getDate() === day
);
}
校验码比对
用本体码根据规则计算出校验码,再和原本的校验码做比对:
function checkCheckNumber(id: string) {
// 分别截取本体码和校验码
const masterNumber = id.slice(0, 17);
const checkNumber = id.slice(-1).toUpperCase();
// 通过上文的方法计算出校验码
const calcCheckNumberResult = calcCheckNumber(masterNumber);
return calcCheckNumberResult === checkNumber;
}
参考文档
- 国家标准 GB 11643-1999:公民身份号
大家好,我是 funkyfang,如果觉得文章还不错,希望大家 点赞、关注和转发,您的支持是我持续更新的动力。🙇🏻
更多内容关注公众号 FunkyCoding
Peace & Love ❤️