1.api项目建库和设计数据库的技巧。一个对象,一张表,一张表,一个主键。表名以数据库名为前缀,字段名以表名为前缀。数据表的关系处理2.为api项目编写接口文档用户登录示例#判断数据库中是否有该用户postwww.test.com/apiapi.test.com参数必填类型说明timetrueint时间戳(用于判断接口访问时间)tokentruestring判断访问者身份(MD5(USER_MD5(time)_USER))usernametruestring只接受邮箱passwordtruestringuserpassword{"ret":200,//返回结果状态。200:接口请求和返回正常/40*:服务器上的数据不正确/500:服务器运行错误"data":{"user_id":"27",//用户id"user_tag":"1"//用户身份},"msg":""//401:用户名不存在!/402:手机号不存在!/403:密码错误!}三、配置URL需求分析·api.test.com===>www.test.com/index.php/api配置api的二级域名打开httpd-vhosts.conf添加ServerAliasapi.test.com配置host文件127.0.0.1api。test.com使用tp5路由进行URL解析新建User.php文件,路径G:tp5/application/api/controller/User.php';回声$id;}}修改config.php(开启路由)//是否开启路由'url_route_on'=>true,//域名部署'url_domain_deploy'=>true,配置路由规则route.phpwww.test.com/index.php/apiRoute::domain('api','api');四、接口安全常见安全问题秤调用消耗系统资源,影响系统正常访问,甚至导致系统崩溃解决方法:获取时间戳(timestamp),设置接口失效时间接口数据被黑客篡改(伪造请求)解决方案:加密参数,生成token,判断token数据是否被黑客截获?解决方案:使用https使用证书加密数据。即使数据被拦截,对黑客来说也毫无意义。黑客可以获得数据,但无法获得数据的加密方式。API项目安全设计时间戳,用于判断请求是否超时,设置为30秒。Token等参数经过加密,保证数据不被篡改。敏感信息加密传输。收到加密后的用户密码。永远不会返回用户密码。最好使用https,所有信息都会被加密。,开发前准备(参数过滤)使用common.php处理参数过滤G:tp5/application/api/controller/Common.phparray(...);protectedfunction_initialize(){parent::_initialize();$this->request=Request::instance();$this->check_time($this->request->only(['时间']));$this->check_token($this->request->param());$this->params=$this->check_params($this->request->except(['time','token']));}自定义返回信息函数G:tp5/application/api/controller/Common.php/***api数据返回*@param[int]$code[resultcode200:normal/4**数据问题/5**Serverproblem]*@param[string]$msg[接口要返回的提示信息]*@param[array]$data[接口要返回的数据]*@return[string][最后是json数据]*/publicfunctionreturn_msg($code,$msg='',$data=[]){/**********组合数据***********/$return_data['code']=$代码;$return_data['msg']=$msg;$return_data['数据']=$数据;/**********返回信息并终止脚本************/echojson_encode($return_data);die;}ValidationtimeG:tp5/application/api/controller/Common.php/***验证请求是否超时*@param[数组]$arr[包含时间戳的参数数组]*@return[json][测试结果]*/publicfunctioncheck_time($arr){if(!isset($arr['time'])||intval($arr['time'])<=1){$this->return_msg(400,'时间戳不正确!');}如果(time()-intval($arr['time'])>60){$this->return_msg(400,'请求超时!');}}verifytokenG:tp5/application/api/controller/Common.php/***Verifytoken(防止篡改数据)*@param[array]$arr[所有请求参数]*@return[json][token验证result]*/publicfunctioncheck_token($arr){/*************从api传来的token************/if(!isset($arr['token'])||empty($arr['token'])){$this->return_msg(400,'token不能为空!');}$app_token=$arr['token'];//从api传递的令牌/**********服务器终端生成令牌***********/unset($arr['token']);$service_token='';foreach($arras$key=>$value){$service_token.=md5($value);}$service_token=md5('api_'.$service_token.'_api');//服务器端即时生成token/**********比较token并返回结果***********/if($app_token!==$service_token){$this->return_msg(400,'令牌值不正确!');}}为每个接口配置验证规则G:tp5/application/api/controller/Common.php比如protected$rules=array('User'=>array('login'=>array('user_name'=>['require','chsDash','max'=>20],'user_pwd'=>'require|length:32',),),);认证参数G:tp5/application/api/controller/Common.php/***认证参数过滤*@param[array]$arr[除time和token之外的所有参数]*@return[return][限定参数数组]*/publicfunctioncheck_params($arr){/************获取参数的校验规则************/$rule=$this->规则[$this->request->controller()][$this->request->action()];/**********验证参数并返回错误*************/$this->validater=newValidate($rule);如果(!$this->validater->check($arr)){$this->return_msg(400,$this->validater->getError());}/**********如果正常,则验证通过************/return$arr;}五、获取验证码验证码生成原理然后发送点击获取验证码发送邮箱号码到后台生成邮箱验证码用session保存验证码,用邮箱发送邮件验证获取用户输入的验证码,取出session中保存的内容进行对比验证返回信息,结束配置路由G:tp5/application/route.php注意:get方法没有参数名,注意参数的顺序,并查看个数//获取验证codeRoute::get('code/:time/:token/:username/:is_exist','code/get_code');参数过滤G:tp5/application/api/controller/Common.php在common.php中简单过滤,具体校验放在code.php'Code'=>array('get_code'=>array('username'=>'require','is_exist'=>'require|number|length:1',)),检测用户名G:tp5/application/api/controller/Code.phpnamespaceapp\api\controller;usephpmailer\phpmailer;usesubmail\messagexsend;classCodeextendsCommon{publicfunctionget_code(){$username=$this->params['username'];$exist=$this->params['is_exist'];$username_type=$this->check_username($username);//检查用户名并决定以下哪个函数switch($username_type){case'phone':$this->get_code_by_username($username,'phone',$exist);//通过手机获取验证码break;case'email':$this->get_code_by_username($username,'email',$exist);//通过邮箱获取验证码break;Common.php中写一个函数publicfunctioncheck_u判断用户名类型sername($username){/**********判断是否为邮箱地址************/$is_email=Validate::is($username,'email')?1:0;/**********判断是否是手机************/$is_phone=preg_match('/^1[34578]\d{9}$/',$用户名)?4:2;/**********最终结果************/$flag=$is_email+$is_phone;switch($flag){/**********notphonenotemail***********/case2:$this->return_msg(400,'电子邮件或电话号码是不正确!');休息;/**********是电子邮件不是电话*************/case3:return'email';休息;/*************是电话不是电子邮件***********/case4:return'phone';休息;}}通过用户名(手机/邮箱)获取验证码G:tp5/application/api/controller/Code.phppublicfunctionget_code_by_username($username,$type,$exist){if($type=='phone'){$type_name='电话';}else{$type_name='邮箱';}/************检测手机号/邮箱是否存在*********/$this->check_exist($username,$type,$exist);/***********每30秒检查一次验证码请求频率**********/if(session("?".$username.'_last_send_time')){if(time()-session($username.'_last_send_time')<30){$this->return_msg(400,$type_name.'验证码,每30秒只能发送一次!');}}/**********生成验证码************/$code=$this->make_code(6);/************使用session存储验证码方便对比,md5加密************/$md5_code=md5($username.'_'.md5($代码));会话($用户名。'_code',$md5_code);/***********使用session存储验证码发送时间************/session($username.'_last_send_time',time());/***********发送验证码*************/if($type=='phone'){$this->send_code_to_phone($username,$代码);}else{$this->send_code_to_email($username,$code);}}判断用户名(手机/邮箱)是否应该存在于数据库中(因为有两种情况1,注册2,修改)我们注册的时候不能存在于数据库中,修改的时候一定有G在数据库:tp5/application/api/controller/Common.phppublicfunctioncheck_exist($value,$type,$exist){$type_num=$type=="phone"?2:4;$flag=$type_num+$exist;$phone_res=db('user')->where('user_phone',$value)->find();$email_res=db('user')->where('user_email',$value)->find();switch($flag){/************2+0phone不需要存在**************/case2:if($phone_res){$this->return_msg(400,'此电话号码已被占用!');}休息;/**********2+1电话需要存在*************/case3:if(!$phone_res){$this->return_msg(400,'此电话号码不存在!');}休息;/***********4+0电子邮件不需要存在*************/case4:if($email_res){$this->return_msg(400,'此邮箱已被使用!');}休息;/**********4+1电子邮件需要存在*************/case5:if(!$email_res){$this->return_msg(400,'该邮箱不存在!');}休息;}}在Code.php中生成验证码publicfunctionmake_code($num){$max=pow(10,$num)-1;$min=pow(10,$n嗯-1);returnrand($min,$max);}只引入email发送验证码打开emailsmtpphp打开php_opensslG:tp5/application/api/controller/Code.phppublicfunctionsend_code_to_email($email,$code){$toemail=$email;$mail=newPHPMailer();$邮件->isSMTP();$mail->CharSet='utf8';//设置字符集$mail->Host='smtp.qq.com';//smtp服务器$mail->SMTPAuth=true;$mail->用户名="123456789@qq.com";$mail->密码="asd1151sad51dsa";//自己设置的smtp密码与登录密码无关$mail->SMTPSecure='ssl';$邮件->端口=465;$mail->setFrom('123456789@qq.com','接口测试');$mail->addAddress($toemail,'test');$mail->addReplyTo('123456789@qq.com','lee');$mail->Subject="您有一个新的验证码!";//邮件主题$mail->Body="这是一封测试邮件,您的验证码为$code,验证码有效期为1分钟,请勿回复此邮件!";//邮件内容if(!$mail->send()){$this->return_msg(400,$mail->ErrorInfo);}else{$this->return_msg(200,'验证码发送成功,请查收!');}}
