在近期的项目中, 我们需要将手机号作为 URL 中的参数, 类似: http://www.***.com/18200001234 这种, 但是手机号这样明文显示又不太安全, 为防止用户恶意篡改 URL 的参数, 于是就选择用 Base64 进行编码了.
Base64 是一种任意二进制到文本字符串的编码方法, 常用于在 URL,Cookie, 网页中传输少量二进制数据.
有时候我们在 Url 传递的参数包含特殊字符 "+","/","=" 时, 这些字符作为参数是不能正常接收的, 或者我们的参数包含了用户的信息比如手机号, 用户 id 等, 我们不想明文显示, 这时候都可以使用 base64 编码.
编码使用到的工具类 Base64Utils. 它是 Spring-core 中提供的, 在 spring-core.jar 中的 org.springframework.util 包下, 它下面常用的工具类还有: StringUtils,ObjectUtils,NumberUtils 等.
首先验证手机号参数的规范性:
- /* 校验手机号正则表达式 */
- final static Pattern PHONE_PATTERN = Pattern.compile("^1(3[0-9]|4[57]|5[0-35-9]|6[0-9]|7[0-9]|8[0-9]|9[8-9])\\d{8}$");
- public static boolean verifyPhone(String tephone){
- if (tephone == null || "".equals(tephone)) {
- return false;
- }
- Matcher m = PHONE_PATTERN.matcher(tephone);
- return m.matches();
- }
验证通过后对手机号进行编码:
定义一个和手机号长度 11 位相同长度的字节数组, 数组里的字符可以是 a-z,0-9 的任意字符, 并且使用异或的规则编码, 保证 URL 解析不发生异常采取 "url safe" 编码方式
- /**
- * 通过手机号获取手机号对应的编码 code
- * @param phone
- * @return
- */
- public static String getLinkByPhone(String phone){
- byte []key = {'A','B','C','D','E','F','G','H', 'I', 'J', 'K'};
- byte []temp = new byte[11];
- if(verifyPhone(phone)){
- for (int i = 0; i <phone.length(); i++) {
- temp[i] = (byte)(key[i] ^ phone.charAt(i));
- }
- }
- return Base64Utils.encodeToUrlSafeString(temp);
- }
然后根据编码的规则定义解码规则:
同样, 定义一个和手机号长度 11 位相同长度的字节数组, 为防止数组越界抛异常我们需要校验参数的合法性
- /**
- * 通过编码后的字符获取对应的手机号
- * @param code
- * @return
- */
- public static String getPhoneByLink(String code){
- byte []temp = new byte[11];
- try {
- byte []key = {'A','B','C','D','E','F','G','H', 'I', 'J', 'K'};
- if(StringUtils.isNotBlank(code)){
- byte []phoneByte = Base64Utils.decodeFromUrlSafeString(code);
- if(phoneByte != null && phoneByte.length> 0 && phoneByte.length <= 11 ){
- for (int i = 0; i < phoneByte.length; i++) {
- temp[i] = (byte)(key[i] ^ phoneByte[i]);
- }
- }
- }
- }catch (Exception e){
- e.printStackTrace();
- }finally {
- return new String(temp);
- }
- }
最后运行结果:
- public static void main(String args[]){
- System.out.println("对手机号编码后:"+getLinkByPhone("18200001234"));
- System.out.println("解码后的手机号:"+getPhoneByLink("cHpxdHV2d3l7eX8="));
- }
base64 对手机号编码解码结果
编码字符串最后的 "=" 是补齐, 因为 base64 编码后的字符长度应该是 4 的倍数, 不足的话会使用 "=" 号补齐, 如果不喜欢这个 "=" 号我们可以过滤掉, 如下:
- public static String getLinkByPhone(String phone){
- byte []key = {'A','B','C','D','E','F','G','H', 'I', 'J', 'K'};
- byte []temp = new byte[11];
- if(verifyPhone(phone)){
- for (int i = 0; i < phone.length(); i++) {
- temp[i] = (byte)(key[i] ^ phone.charAt(i));
- }
- }
- /* 去掉最后补齐的 = 符号 */
- String result = Base64Utils.encodeToUrlSafeString(temp);
- return result.substring(0,result.length()-1);
- }
总结:
Base64 编码是从二进制到字符的转换过程, 并不是真正的加密方式, 说 Base64 编码是加密方法, 只是因为经过 Base64 编码之后, 让人一眼看上去不知道什么内容而已.
关于将手机号转换成加密字符串的方式还有很多, 这里只是一种方法的记录.
来源: http://www.jianshu.com/p/172ba435cc9d