數據庫名
作前綴表名
作前綴縮寫
(容易看懂的前提下)用戶登陸
舉例javascript
# 判斷數據庫中是否有此用戶
post
www.test.com/apiapi.test.com
參數 | 必選 | 類型 | 說明 |
---|---|---|---|
time | true | int | 時間戳 (用於肯定接口的訪問時間) |
token | true | string | 肯定訪問者身份 (MD5(USER_MD5(time)_USER) ) |
username | true | string | 只接受郵箱 |
password | true | string | 用戶密碼 |
{ "ret": 200, // 返回結果狀態。200:接口正常請求並返回/40*:服務端的數據有誤/500:服務器運行錯誤 "data": { "user_id": "27", // 用戶id "user_tag": "1" // 用戶身份 }, "msg": "" // 401:用戶名不存在!/402:手機號不存在!/403:密碼不正確! }
· api.test.com
===> www.test.com/index.php/api
php
httpd-vhosts.conf
添加 ServerAlias api.test.com
host
文件 127.0.0.1 api.test.com
User.php
文件,路徑 G:tp5/application/api/controller/User.php
<?php namespace app\api\controller; class User{ public function index($id){ echo '<br/>'; echo $id; } }
config.php
(開啓路由)// 是否開啓路由
'url_route_on' => true,
// 域名部署
'url_domain_deploy' => true,
route.php
<?php use think\Route; // api.test.com ===> www.test.com/index.php/api Route::domain('api','api');
解決方案: 獲取 timestamp (時間戳), 設置接口失效時間
解決方案: 對參數加密, 生成 token , 判斷 token 是否正確
解決方案: 使用 https , 用證書對數據進行加密, 即便數據被截取, 對黑客也沒有意義
時間戳, 用於判斷請求是否超時, 設置爲30秒
其餘參數加密而來, 保證數據不被篡改
接收加密過的用戶密碼, 用戶密碼永不返回
最好使用 https, 全部信息都會被加密
使用 common.php
統一處理參數過濾 G:tp5/application/api/controller/Common.php
java
<?php namespace app\api\controller; use think\Controller; use think\Request; use think\Validate; class Common extends Controller { protected $request; // 用來處理參數 protected $validater; // 用來驗證數據/參數 protected $params; // 過濾後符合要求的參數 protected $rules = array( 'User'=>array(......); protected function _initialize() { parent::_initialize(); $this->request = Request::instance(); $this->check_time($this->request->only(['time'])); $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 [結果碼 200:正常/4**數據問題/5**服務器問題] * @param [string] $msg [接口要返回的提示信息] * @param [array] $data [接口要返回的數據] * @return [string] [最終的json數據] */ public function return_msg($code, $msg = '', $data = []) { /*********** 組合數據 ***********/ $return_data['code'] = $code; $return_data['msg'] = $msg; $return_data['data'] = $data; /*********** 返回信息並終止腳本 ***********/ echo json_encode($return_data);die; }
驗證 time
G:tp5/application/api/controller/Common.php
json
/** * 驗證請求是否超時 * @param [array] $arr [包含時間戳的參數數組] * @return [json] [檢測結果] */ public function check_time($arr) { if (!isset($arr['time']) || intval($arr['time']) <= 1) { $this->return_msg(400, '時間戳不正確!'); } if (time() - intval($arr['time']) > 60) { $this->return_msg(400, '請求超時!'); } }
驗證token G:tp5/application/api/controller/Common.php
api
/** * 驗證token(防止篡改數據) * @param [array] $arr [所有請求參數] * @return [json] [token驗證結果] */ public function check_token($arr) { /*********** api傳過來的token ***********/ if (!isset($arr['token']) || empty($arr['token'])) { $this->return_msg(400, 'token不能爲空!'); } $app_token = $arr['token']; // api傳過來的token /*********** 服務器端生成token ***********/ unset($arr['token']); $service_token = ''; foreach ($arr as $key => $value) { $service_token .= md5($value); } $service_token = md5('api_' . $service_token . '_api'); // 服務器端即時生成的token /*********** 對比token,返回結果 ***********/ if ($app_token !== $service_token) { $this->return_msg(400, 'token值不正確!'); } }
爲每一個接口配置驗證規則 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] [合格的參數數組] */ public function check_params($arr) { /*********** 獲取參數的驗證規則 ***********/ $rule = $this->rules[$this->request->controller()][$this->request->action()]; /*********** 驗證參數並返回錯誤 ***********/ $this->validater = new Validate($rule); if (!$this->validater->check($arr)) { $this->return_msg(400, $this->validater->getError()); } /*********** 若是正常,經過驗證 ***********/ return $arr; }
驗證碼原理服務器
點擊獲取驗證碼
發送郵箱號到後臺
後臺生成郵箱驗證碼
用session保存驗證碼及郵箱
發送郵件
獲取用戶輸入的驗證碼及郵箱
取出session保存的內容
對比驗證
返回信息, 結束
配置路由 G:tp5/application/route.php
session
注意: get方式沒有參數名, 因此要注意參數的順序, 對號入座.
// 獲取驗證碼 Route::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.php
namespace app\api\controller; use phpmailer\phpmailer; use submail\messagexsend; class Code extends Common { public function get_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
中寫一個判斷用戶名類型的函數
public function check_username($username) { /*********** 判斷是否爲郵箱 ***********/ $is_email = Validate::is($username, 'email') ? 1 : 0; /*********** 判斷是否爲手機 ***********/ $is_phone = preg_match('/^1[34578]\d{9}$/', $username) ? 4 : 2; /*********** 最終結果 ***********/ $flag = $is_email + $is_phone; switch ($flag) { /*********** not phone not email ***********/ case 2: $this->return_msg(400, '郵箱或手機號不正確!'); break; /*********** is email not phone ***********/ case 3: return 'email'; break; /*********** is phone not email ***********/ case 4: return 'phone'; break; } }
經過用戶名(手機/郵箱)獲取驗證碼 G:tp5/application/api/controller/Code.php
public function get_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)); session($username . '_code', $md5_code); /*********** 使用session存儲驗證碼的發送時間 ***********/ session($username . '_last_send_time', time()); /*********** 發送驗證碼 ***********/ if ($type == 'phone') { $this->send_code_to_phone($username, $code); } else { $this->send_code_to_email($username, $code); } }
判斷用戶名(手機/郵箱)在數據庫中是否應該存在(由於要分兩種狀況1,註冊 2,修改)
當咱們註冊的時候數據庫裏不能有,當咱們修改的時候數據庫裏必須有G:tp5/application/api/controller/Common.php
public function check_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+0 phone need no exist ***********/ case 2: if ($phone_res) { $this->return_msg(400, '此手機號已被佔用!'); } break; /*********** 2+1 phone need exist ***********/ case 3: if (!$phone_res) { $this->return_msg(400, '此手機號不存在!'); } break; /*********** 4+0 email need no exist ***********/ case 4: if ($email_res) { $this->return_msg(400, '此郵箱已被佔用!'); } break; /*********** 4+1 email need exist ***********/ case 5: if (!$email_res) { $this->return_msg(400, '此郵箱不存在!'); } break; } }
在 Code.php
中生成驗證碼
public function make_code($num) { $max = pow(10, $num) - 1; $min = pow(10, $num - 1); return rand($min, $max); }
只介紹郵箱發送驗證碼
開啓郵箱smtp
php 開啓php_openssl
G:tp5/application/api/controller/Code.php
public function send_code_to_email($email, $code) { $toemail = $email; $mail = new PHPMailer(); $mail->isSMTP(); $mail->CharSet = 'utf8'; // 設置字符集 $mail->Host = 'smtp.qq.com'; // smtp服務器 $mail->SMTPAuth = true; $mail->Username = "123456789@qq.com"; $mail->Password = "asd1151sad51dsa"; // 本身設置的smtp密碼, 與登陸密碼無關 $mail->SMTPSecure = 'ssl'; $mail->Port = 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, '驗證碼已經發送成功,請注意查收!'); } }