api接
路由
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Route::group(['namespace' => 'Api','middleware' =>['myapi']], function(){
#登录接口
Route::any('/user/login','UserController@login');
#登录接口
Route::any('/login2','UserController@login2');
#发送短信验证码
Route::any('/sendSms','PublicController@sendSms');
#获取图片验证码的链接
Route::any('/getImageCodeUrl','PublicController@getImageCodeUrl');
#注册
Route::any('/register','UserController@register');
});
#展示图片验证码,不需要加密解密
Route::any('/imageCode','Api\PublicController@imageCode');
#测试session
Route::any('/SessionTest','Api\PublicController@SessionTest');
apiCheck中间接
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class ApiCheck
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
# 接受客户端传过来的data数据
#因为客户端传递的数据是加密的,所以需要把数据解密回来
if($data=$request->post('data')){
#判断接口是否开启加密
if(env('API_ENCRYPT')){
#对称加密
if(env('API_ENCRYPT_TYPE')==1)
{
if(is_string($data)){
$decrypt_data = $this->AesDecrypt($data);
}else{
$decrypt_data =[];
}
#非对称加密
}else{
if(is_string($data)){
$decrypt_data = $this->RsaDecrypt($data);
}else{
$decrypt_data =[];
}
}
}else{
$decrypt_data =$data;
}
}else{
$decrypt_data =[];
}
// dd($decrypt_data);
# 把接收的数据做一个替换
$request -> replace((array)$decrypt_data);
$response = $next($request);
return $response;
}
/**
* AES解密
*/
private function AesDecrypt($data_str)
{
#加密
$key=env('AES_KEY');
$iv =env('AES_IV');
#AES解密
$decrypt_data=base64_decode($data_str);#反编码
$origin_data=openssl_decrypt(
$decrypt_data,
'AES-256-CBC',
$key,
OPENSSL_RAW_DATA,
$iv
);
// var_dump($origin_data);exit;
return json_decode($origin_data,true);
}
/**
* RSA解密
*/
private function RsaDecrypt($data_str)
{
#解密的方法
$all = base64_decode($data_str);#反编码
$j=1;
$all_new='';
while($sub_str=substr($all,($j -1)*128,128)){
openssl_private_decrypt(
$sub_str,
$decrypt,
file_get_contents(public_path() . '/private.key'),
OPENSSL_PKCS1_PADDING
);
$all_new .=$decrypt;
$j++;
}
return json_decode($all_new,true);
}
}
UserController控制器
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\CommonController;
use App\models\MessageModel;
use App\models\UserModel;
use App\models\UserTokenModel;
use App\ParamMsg\Error;
use Illuminate\Http\Request;
/*用户相关的接口*/
class UserController extends CommonController
{
// 登录接口
/*
// public function login(Request $request)
// {
/* var_dump($request ->all());exit;
$arr=[
'status'=>200,
'msg'=>'登录成功',
'data'=>[]
];
return $arr;*/
public function login(Request $request)
{
// var_dump($request->all());exit;
#接受用户的名字
$user_name = $this -> checkParamIsEmpty('user_name');
#接受密码
$password = $this -> checkParamIsEmpty('password');
#接受下登录的终端类型
$tt = $this -> checkParamIsEmpty('tt');
#去数据库查询用户是否存在
$where=[
['user_name','=',$user_name]
];
$user_obj=UserModel::where($where)->first();
// var_dump($user_obj);exit;
#判断用户是否存在
if(empty($user_obj)){
$this->showApiError('user_not_exists');
}else{
#检查用户的状态是否可以正常登陆
$this->checkUserStatus($user_obj);
#数据的密码是md5(密码+随机码)
$user_input_password=md5($password.$user_obj->rand_code);
#判断用户名和密码一致
if($user_input_password==$user_obj -> password){
#成功返回用户信息 todo 这一块需要继续完善token相关功能
$user_info=$user_obj->toArray();
#获取用户id
$user_id=$user_info['user_id'];
#返回一个登录的令牌,后续调用接口的时候需要用到
$user_info['token']=$this->_creatUserToken($user_id,$tt);
#登录成功,重置用户的错误次数
$user_obj->error_count=null;
$user_obj->last_error_time=null;
$user_obj->save();
return $this->success($user_info);
}else{
#给出对应提示信息
// $this->showApiError('user_password_not_match');
#为了防止暴力破解,1小时内,连续错误5次之后,把账号锁定2小时
$this->showApiError('',$this->userErrorCount($user_obj));
}
}
}
/**
* 记录用户的错误次数 1小时内,连续错误5次之后,把账号锁定2小时
* @param UserModel $user_obj
*/
private function userErrorCount(UserModel $user_obj){
#获取当前时间
$now=time();
#包含错误信息的数组
$msg_arr= Error::MSG;
#若错误时间在二个小时 并且错误次数超过五次 提示现在是锁定状态
if($now - $user_obj->last_error_time < 7200 && $user_obj->error_count >= 5){
return sprintf($msg_arr['user_lock_two_hour'],date('H:i:s',$user_obj->last_error_time+7200));
}
#如果超过两个小时后 重新计算错误次数 变成 1 若未超过二小时就增加错误次数
#一小时内错误5次 锁定账号
if($now - $user_obj->last_error_time>=3600){
$error_count=1;
}else{
$error_count = $user_obj->error_count+1;
}
#当错误次数为1 或 5时 需要记录 错误时间 便于 判断 (1为开头 5为结束)
if($error_count==1 || $error_count==5){
$user_obj->last_error_time = $now;
}
$user_obj->error_count =$error_count;
#取出错误次数的提示信息 变成错误次数动态提示
$error_msg = sprintf($msg_arr['password_error'],$error_count);
#错误五次的时候,给出对应的提示
if( $error_count==5){
$error_msg= sprintf($msg_arr['user_lock_two_hour'],date('H:i:s',$user_obj->last_error_time+7200));
}
#判断数据库是否保存成功 成功给出 动态错误提示信息 失败 给出 密码错误提示信息
if($user_obj->save()){
return $error_msg;
}else {
return $msg_arr['user_password_not_match'];
}
}
/*生成用户对应的token 默认有效期是1天*/
protected function _creatUserToken($user_id,$tt=1)
{
#为了防止用户频繁的登录,每次都生成token
$new =time();
$where=[
['user_id','=',$user_id],
['ctime','>', $new - 60],
['login_type','=',$tt]
];
#限制用户同一个终端一分钟只能登录三次 【登录成功】
if(UserTokenModel::where($where)->count() >=3 ){
$this->showApiError('many_login_success');
}
#把令牌写入数据库中
$user_token_model=new UserTokenModel();
$user_token_model->user_id = $user_id;
#生成不重复令牌
$user_token_model ->token=md5(uniqid());
$user_token_model->expire=time()+86400;
$user_token_model->login_type = $tt;
$user_token_model->status =1;
$user_token_model->ctime=time();
#保存用户的令牌
if($user_token_model -> save()){
return $user_token_model-> token;
}else{
return false;
}
}
/**
* 注册
*/
public function register(Request $request)
{
#短信验证码
#手机号
#密码
$phone=$this->checkParamIsEmpty('phone');
$password=$this->checkParamIsEmpty('password');
$message_code=$this->checkParamIsEmpty('mcode');
#取出改手机号对应的验证码
$where=[
['phone','=',$phone]
];
$m_obj=MessageModel::where($where)
->orderBy('id','desc')
->first();
#判断该手机号是否存在
if(empty($m_obj)){
$this->showApiError('phone_message_empty');
}
#验证验证码是否正确
if($m_obj->rand_code != $message_code){
$this->showApiError('message_code_error');
}
#验证码只有2分钟的有效期
$now=time();
#说明超过2分钟
if($now-$m_obj->ctime>120){
$this->showApiError('message_code_expire');
}
#用户数据写入数据表
#生成用户随机码
$rand_code=rand();
$user_model=new UserModel();
$user_model->phone=$phone;
$user_model->rand_code=$rand_code;
$user_model->password=md5($password.$rand_code);
$user_model->status=3;
$user_model->ctime=time();
if($user_model -> save() ){
return $this->success();
}else{
$this->showApiError('register_fail');
}
}
/*登录接口+前端使用js请求,格式是jsonp
public function login(Request $request)
{
//接收传过来的get请求的数据
$call=$request->get('callback');
$arr=[
'status'=>200,
'msg'=>'',
'data'=>[]
];
echo $call.'('.json_encode($arr).')';
exit;
}
public function login2(Request $request)
{
$arr=[
'status'=>200,
'msg'=>'',
'data'=>[]
];
return $arr;
}*/
}
公共的
<?php
namespace App\Http\Controllers;
use App\models\UserModel;
use App\ParamMsg\Error;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
/*API控制器的基类 所有API接口需要继承这个控制器*/
class CommonController extends Controller
{
/*显示API的相关错误*/
protected function showApiError($key,$msg='')
{
if($msg !=''){
return $this->fail($msg);
}else{
#给出对应的提示
return $this->fail( $this -> getErrorMsg ($key),100);
}
}
//购买链接
https://market.aliyun.com/products/56928004/cmapi023305.html?spm=5176.10695662.1996646101.searchclickresult.4c1519fbrg125p#sku=yuncode1730500007
/**
* 发送短信的方法
*/
public function sendAliSms($phone,$sms_code)
{
return true;exit;
$host = "http://dingxin.market.alicloudapi.com";
$path = "/dx/sendSms";
$method = "POST";
$appcode = "";//你自己的AppCode
$headers = array();
array_push($headers, "Authorization:APPCODE " . $appcode);
$querys = "mobile=".$phone."¶m=code%3A".$sms_code."&tpl_id=TP1711063";
$bodys = "";
$url = $host . $path . "?" . $querys;
$curl=curl_init();
curl_setopt($curl,CURLOPT_CUSTOMREQUEST,$method);
curl_setopt($curl,CURLOPT_URL,$url);
curl_setopt($curl,CURLOPT_HTTPHEADER,$headers);
curl_setopt($curl,CURLOPT_FAILONERROR,false);
curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
curl_setopt($curl,CURLOPT_HEADER,false);
if(1==strpos("$".$host,"https://")){
curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,false);
}
$curl_result=curl_exec($curl);
// var_dump($curl_result);exit;
$curl_arr=json_decode($curl_result,true);
// var_dump(curl_exec($curl));
if(!empty($curl_arr) && $curl_arr['return_code']=='00000'){
return true;
}else{
return false;
}
}
/**
* 检查用户的状态
* @return
*/
protected function checkUserStatus($user_obj='',$user_id='')
{
if(!empty($user_obj) && $user_obj instanceof UserModel ){
#判断用户状态 1待审核 2锁定 3正常 4已删除
if($user_obj->status==1){
$this->showApiError('user_not_check');
}elseif(($user_obj->status==2)){
$this->showApiError('user_is_lock');
}elseif(($user_obj->status==4)){
$this->showApiError('user_is_del');
}
#判断用户是否连续输错密码超过限制
#获取当前时间
$now=time();
#包含错误信息的数组
$msg_arr= Error::MSG;
#若错误时间在二个小时 并且错误次数超过五次 提示现在是锁定状态
if($now - $user_obj->last_error_time < 7200 && $user_obj->error_count >= 5){
$this->showApiError('',
sprintf(
$msg_arr['user_lock_two_hour'],
date('H:i:s',$user_obj->last_error_time+7200)
)
);
}
}
}
/*获取对应的错误提示信息*/
public function getErrorMsg($key)
{
$error_all=Error::MSG;
if(isset($error_all[$key])){
$error_msg=$error_all[$key];
}else{
$error_msg='出现错误了';
}
return $error_msg;
}
/*检查参数是否为空*/
protected function checkParamIsEmpty($key)
{
#接受客户端传递的参数
$request_data=request()->all();
#判断是否传递参数
if(empty($request_data[$key])){
#给出对应的提示
return $this-> fail($this->getErrorMsg($key),1000);
}else{
#没有问题的时候,返回对应的值
return $request_data[$key];
}
}
/*失败的时候的提示信息*/
protected function fail($msg='fail',$status=1,$data=[])
{
$arr=$this->jsonOutPut($status,$msg,$data);
// return response($arr);
echo json_encode($arr, JSON_UNESCAPED_UNICODE );
exit;
}
/*成功的提示信息*/
protected function success($data=[], $status=200,$msg='success')
{
return $this->jsonOutPut( $status,$msg,$data);
}
/*统一的数据返回*/
private function jsonOutPut( $status,$msg,$data)
{
return[
'status'=>$status,
'msg'=>$msg,
'data'=>$data
];
}
}
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\CommonController;
use App\models\MessageModel;
use App\models\UserModel;
use Illuminate\Http\Request;
class PublicController extends CommonController
{
/**
* 测试Sessionid 传值
* @param Request $request
*/
public function SessionTest(Request $request)
{
// $request->session()->setId($request->get('sid'));
// $request->session()->start();
// $sid=$request->session()->getId();
//// var_dump($sid);
//// $request->session()->put(['user_name'=>'xiaoxiao']);
// var_dump( $request->session()->get('user_name'));
}
/**
* 发送短信验证码
*/
public function sendSms(Request $request)
{
$phone = $this->checkParamIsEmpty('phone');
$sid = $this->checkParamIsEmpty('sid');
$image_code = $this->checkParamIsEmpty('image_code');
#发送短信验证码
# 1、先判断手机号是否已经注册过
$where=[
['phone','=',$phone]
];
#2、判断用户是否存在
if(UserModel::where($where)->count()>0){
#给出对应的提示信息
$this->showApiError('phone_already_exists');
}
#3、验证图片验证码是否正确
$request->session()->setId($sid);
$request->session()->start();
$code=$request->session()->get('image_code');
#4、验证码不正确给出对应提示信息
// if($image_code !='8888'&& $code !=$image_code)
if($code !=$image_code)
{
$this->showApiError('image_code_error');
}
#发送短信验证码
#限制短信发送的频率【同一个1天最多发送10条,每条1分钟的可以发送一次】
#限制1天最多发送10条
$today_start=strtotime(date('Y-m-d'));
$today_end=$today_start+86400;
$where=[
['phone','=',$phone],
['ctime','>=',$today_start],
['ctime','<=',$today_end]
];
#一天内超过10条不让继续发送
if(MessageModel::where($where)->count() >=10){
$this->showApiError('send_more_message');
}
#限制1分钟才能继续发送
$where=[
['phone','=',$phone],
['ctime','>=',time()-60],
];
#每次发送时间超过1分钟
if(MessageModel::where($where)->count()>=1){
$this->showApiError('message_one_minute_limit');
}
#先调用短信发送接口
$sms_code=rand(100000,999999);
#调用短信发送接口
if($this->sendAliSms($phone,$sms_code))
{
$model=new MessageModel();
$model->phone=$phone;
$model->rand_code=$sms_code;
#1注册 2找回密码
$model->message_type=1;
$model->message_content=$sms_code;
$model->is_send=1;
$model->status=1;
$model->ctime = time();
if($model->save()){
return $this->success();
}else{
$this->showApiError('message_send_error');
}
}else{
$this->showApiError('message_send_error2');
}
}
/**
* 获取图片验证码的url
*/
public function getImageCodeUrl(Request $request)
{
$request->session()->start();
$sid=$request->session()->getId();
// var_dump($sid);exit;
$domain=str_replace(
$request->path(),
'',
$request->url()
);
$image_code_url=$domain.'imageCode?sid='.$sid;
$api_return_arr=[
'image_url'=>$image_code_url,
'sid'=>$sid
];
return $this->success($api_return_arr);
}
/**
* 图片验证码
* @param Request $request
*/
public function imageCode(Request $request)
{
// dd($request->all());
$sid=$request->get('sid');
// var_dump($sid);exit;
if(empty($sid)){
$this->showApiError('','缺少必须参数!');
}
#要在画板上写文字
$text= ''.rand(1000,9999);
#指定当前的会话id
$request->session()->setId($sid);
$request->session()->start();
#开启session
$request->session()->put('image_code',$text);
#输出图片最后要exit 这个地方收到调用一下save
$request->session()->save();
#告诉浏览器要输出对是png格式对图片
header('Content-Type:image/png');
#创建一个画布
$im=imagecreatetruecolor(100,30);
#创建几个颜色
$white=imagecolorallocate($im,255,255,255);
$black=imagecolorallocate($im,0,0,0);
#画布填充颜色
imagefilledrectangle($im,0,0,339,29,$white);
#设置字体文件
$font=public_path().'/Verdana.ttf';
#画布上写字
$i=0;
while($i<strlen($text)){
if($i==0){
imagettftext($im,20,rand(-15,30),$i * 25,24,$black,$font,$text[$i]);
}else{
imagettftext($im,20,rand(-15,30),$i * 25,24,$black,$font,$text[$i]);
}
$i++;
}
#输出图片
imagepng($im);
imagedestroy($im);
#exit不能省掉
exit;
}
}
错误提示
<?php
namespace App\ParamMsg;
/*接口相关的错误提示信息*/
class Error
{
#接口相关的错误提示信息
const MSG=[
#账户名为空的时候的提示信息
'user_name'=>'用户名不能为空',
#密码不为空的时候的提示信息
'password'=>'你还没有输入密码呢!',
#用户不存在的提示信息
'user_not_exists'=>'你要登陆的账号没有找到',
'user_not_check' =>'你的账号还没有审核通过',
'user_is_lock' =>'你的账号被锁定了,请联系客服给您解锁',
'user_is_del' =>'你要登陆的账号不存在',
'user_password_not_match'=>'账号密码不一致,请核对后,再次尝试',
'tt'=>'请选择你要登录的终端类型',
'many_login_success'=>'登录太过频繁,请等一会,再次尝试',
'password_error'=>'你的账号已经输错%s次,错误5次账号会被锁定2小时',
'user_lock_two_hour'=>'你的账号已经被锁定,请在%s点后在次尝试!',
'phone'=>'请输入你的手机号',
'sid'=>'验证码错误!',
'image_code'=>'请输入图片验证码',
'phone_already_exists'=>'手机号已经存在了',
'image_code_error'=>'图片验证码输入错误',
'send_more_message'=>'一天最多发送10条',
'message_one_minute_limit'=>'短信发送太过频繁',
'message_send_error'=>'短信发送失败,MYSQL插入失败',
'message_send_error2'=>'短信发送失败,请检查!',
'mcode'=>'短信验证码不能为空',
'message_code_expire'=>'短信验证码已过期(2分钟)',
'message_code_error'=>'短信验证码不正确',
'register_fail'=>'注册失败,请重试!',
'phone_message_empty'=>'该手机号不存在,请确认后,在重试!',
];
}
env
APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:259fA+3F5jGtyk0vv6efGwFIC6kOx+M2wk7Ya9Z6N64=
APP_DEBUG=true
APP_URL=http://localhost
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=api_project
DB_USERNAME=root
DB_PASSWORD=lidanyang
BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
AES_KEY="1908phpA"
AES_IV="1213515561561512"
#API是否开启加密 0关闭加密1开启加密
API_ENCRYPT=1
#1对应加密2非对称加密
API_ENCRYPT_TYPE=2
model
1、
<?php
namespace App\models;
use Illuminate\Database\Eloquent\Model;
class MessageModel extends Model
{
protected $table='exam_message';
protected $primaryKey='id';
public $timestamps=false;
protected $guarded=[];
}
2、
<?php
namespace App\models;
use Illuminate\Database\Eloquent\Model;
class UserModel extends Model
{
protected $table='exam_user';
protected $primaryKey='user_id';
public $timestamps=false;
protected $guarded=[];
}
3、
<?php
namespace App\models;
use Illuminate\Database\Eloquent\Model;
class UserTokenModel extends Model
{
//表名
protected $table='exam_user_token';
//主见id
protected $primaryKey='id';
//关闭时间补全
public $timestamps=false;
protected $guarded=[];
}