Android客户端与PHP服务端API接口Token安全验证

滕项明
2023-12-01

Android客户端:

1、写一个生成token的算法

    /**
     * 生成api接口的token
     * @param map
     * @param apikey
     * @return
     */
    public static String createToken(Map<String, String> map,String apikey){
        StringBuffer sb=new StringBuffer();
        for (String value : map.values()) {  
            sb.append(md5(value));
        }
        SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd 00:00:00");
        String time=format.format(new Date());
        //token生成规则:md5(接口密钥+集合数据md5+今天的日期)
        String token=md5(apikey+sb.toString()+time);
        return token;
    }
    /**
     * MD5加密
     * @param plainText 要加密的字符串
     * @return
     */
    public static String md5(String plainText){
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(plainText.getBytes());
            byte b[] = md.digest();

            int i;

            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0)
                    i += 256;
                if (i < 16)
                    buf.append("0");
                buf.append(Integer.toHexString(i));
            }
            //32位加密
            return buf.toString();
            // 16位的加密
            //return buf.toString().substring(8, 24);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

token生成规则可以自己定义,但要保证客户端与服务端计算的Token保持一致。

2、进行post请求时,添加上我们生成的token 

SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time=sdf.format(new Date());
Map<String,String> datamap=new HashMap<String,String>();
datamap.put("type","query");
datamap.put("money",100);
datamap.put("time",time);
//添加token参数
String apikey="dfgdfsgertyrewtretww";
String token=createToken(postmap,apikey);
postmap.put("token",token);
//后面这里就是执行post请求了(此处代码省略)

PHP服务端: 

1、我后端使用的是Thinkphp5.0框架,写个公共的控制器类ApiBase.php

<?php
namespace app\index\controller;
use think\Controller;
use think\Request;

class ApiBase extends Controller
{
    protected function _initialize(){
		parent::_initialize();
		//获取参数
	    $params = Request::instance()->param();
		//验证是否超时
		$this->check_time($params);
		//验证token
		$this->check_token($params); 
    }
	/**
	* api数据返回
	* @param [int] $code [结果码]
	* @param [string] $msg [接口要返回的提示信息]
	* @param [array] $data [接口要返回的数据]
	* @return [string] [最终的json数据]
	*/
	public function return_data($code, $msg = '', $data = []) {
		$return_data['code'] = $code;
		$return_data['msg'] = $msg;
		$return_data['data'] = $data;
		echo json_encode($return_data,JSON_UNESCAPED_UNICODE);
		die;
	}
	/**
	* 验证请求是否超时
	* @param [array] $arr [包含时间戳的参数数组]
	* @return [json] [检测结果]
	*/
	public function check_time($arr) {
		if (!isset($arr['time']) || intval($arr['time']) <= 1) {
			$this->return_data(0,'参数非法');
		}
		//超过5秒则超时
		if (time() - strtotime($arr['time']) > 5) {
			$this->return_data(0,'请求超时');
		}
	}
	/**
	* 验证token(防止篡改数据)
	* @param [array] $arr [全部请求参数]	
	* @return [json] [token验证结果]
	*/
	public function check_token($arr) {
		/*********** api传过来的token ***********/
		if (!isset($arr['token']) || empty($arr['token'])) {
			$this->return_data(0,'Token参数不能为空');
		}
		$api_token = $arr['token'];
		unset($arr['token']);
		/*********** 服务器端生成token ***********/		
		$md5_data = '';
		foreach ($arr as $key => $value) {
			$md5_data .= md5($value);
		}
	    //token生成规则:md5(接口密钥+集合数据md5+今天的日期)
		$service_token = md5(Config('api_key'). $md5_data .date('Y-m-d 00:00:00', time())); 
		/*********** 对比token,返回结果 ***********/
		if ($api_token !== $service_token) {
			$this->return_data(0,'Token令牌不正确');
		}
	}
}

2、api接口控制器实现类,直接继承这个ApiBase.php类即可自动验证token

<?php
namespace app\index\controller;
use think\Controller;
use think\Request;
use think\Cache;

/**
 * Api接口通讯类
 */
class Api extends ApiBase
{  
    public function _initialize(){	
        parent::_initialize(); 
	}
}
 类似资料: