如标题:我想在ajax的header头增加自定义Token进行跨域api认证并调用,api使用laravel5编写,如何实现?
首先,了解下CORS简单请求和复杂请求。
-- CORS简单请求 --
链接:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
1、ajax跨域,使用CORS方式 -- (ajax跨域会自动提交origin字段,用户不可伪造)
2、HTML的js:
</body> <script type="text/javascript"> $(function(){ $(document).on("click", ".btn-all2", function(){ $.ajax({ url:"http://t-local.*****.com/wechat/auth/up?call_back=http%3A%2F%2Ftest.*****.com%2Findex.php%3Fg%3DWeixin%26m%3DWeixin%26a%3Dindex", dataType:"json", type:"get", //origin字段不允许自定义伪造;跨域请求浏览器自动带上origin // 允许携带cookie凭证 xhrFields: { withCredentials: true }, // 允许跨域 crossDomain: true, success:function(data){ console.log(\'success\'); console.log(JSON.stringify(data)); }, error: function(data){ console.log(\'error\'); console.log(JSON.stringify(data)); } }) }) }) </script> </html>
laravel5后台ajax请求过滤中间件: -- laravel 5 用来处理【简单请求】或者【复杂请求的第二次请求】
//跨域XML请求,会自动带上http_origin字段
public function handle( $request, Closure $next )
{
$origin = isset($_SERVER[\'HTTP_ORIGIN\'])? $_SERVER[\'HTTP_ORIGIN\'] : \'\';
$allow_origin = Config::get(\'app.allow_origin\');
$allow_origin_dynamic = Config::get(\'app.allow_origin_dynamic\');
$allowOrigin = false;
if ( in_array( $origin, $allow_origin ))
{
$allowOrigin = true;
} else {
foreach ( $allow_origin_dynamic as $item )
{
if ( strpos( $origin, $item ) !== false )
{
$allowOrigin = true;
break;
}
}
}
if ( $allowOrigin )
{
header(\'Access-Control-Allow-Origin: \'.$origin);
header(\'Access-Control-Allow-Methods:POST,GET,OPTIONS,PUT,DELETE\');
header(\'Access-Control-Allow-Headers:x-requested-with,content-type\');
header(\'Access-Control-Allow-Credentials:true\');
}
return $next($request);
}
------ CORS复杂请求 --------
链接:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
复杂请求 =【预请求 + 简单请求】;
一次XMLHttpRequest会发送两次请求,一次options、一次自定义的请求
那么在TP5中,我们可以使用行为扩展处理ajax|axios 带自定义头token的CORS请求,在laravel5中怎样解决呢?
laravel5 解决方案:
1、域名一:local.domian.com前端发起跨域ajax请求:访问laravel5的t-local.domian.com域名二
<script type="text/javascript"> $(function(){ $(document).on("click", ".btn-all2", function(){ $.ajax({ url:"http://t-local.****.com/api/wechat/auth/up?call_back=http%3A%2F%2Ftest.****.com%2Findex.php%3Fg%3DWeixin%26m%3DWeixin%26a%3Dindex", dataType:"json", type:"get", //origin字段不允许自定义伪造;跨域请求浏览器自动带上origin //自定义请求头认证token headers: { \'token\' : "2211zxz" }, // 允许携带cookie凭证 xhrFields: { withCredentials: true }, // 允许跨域 crossDomain: true, success:function(data){ console.log(\'success\'); console.log(JSON.stringify(data)); }, error: function(data){ console.log(\'error\'); console.log(JSON.stringify(data)); } }) }) }) </script>
2、在laravel的route/api.php路由文件,增加以下路由规则:
/**
* laravel5发送复杂cors请求,类似jwt、自定义请求头token等,会先发送预请求options
* @param : 预请求options的【Access-Control-Allow-Origin:】绝对不可以设置成*,否则报错
* @return : code 200
* date: 2019年10月30日下午2:29:50
* author: xzz
*/
Route::options(\'/{all}\',function () {
//file_put_contents(storage_path(\'logs/SERVER_Header.txt\'), \'array = \' . var_export(request()->header(), true) . PHP_EOL, FILE_APPEND);
//file_put_contents(storage_path(\'logs/SERVER_Header.txt\'), \'string\' . var_export(request()->header(\'ORIGIN\'), true) . PHP_EOL, FILE_APPEND);
$origin = request()->header(\'ORIGIN\')??request()->header(\'HTTP_ORIGIN\');
header("Access-Control-Allow-Origin: $origin");
header("Access-Control-Allow-Credentials: true");
header(\'Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE\');
header(\'Access-Control-Allow-Headers: Origin, Access-Control-Request-Headers, SERVER_NAME, Access-Control-Allow-Headers, cache-control, token, X-Requested-With, Content-Type, Accept, Connection, User-Agent\');
})->where([\'all\' => \'([a-zA-Z0-9-]|/)*\']);
3、返回前端F12打开,发现options请求已通过:
4、在创建一个【ajax简单请求】验证中间件(如果是简单请求,上面都可以省略),App\Middleware\AjaxHeader.php,kernel.php注册在api里面
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Support\Facades\{Config}; class AjaxHeader { /** * @param $request * @param Closure $next * @return mixed */ public function handle( $request, Closure $next ) { file_put_contents(storage_path(\'logs/1.txt\'), var_export($_SERVER, true) . PHP_EOL, FILE_APPEND); file_put_contents(storage_path(\'logs/SERVER_HeaderReal.txt\'), \'array = \' . var_export(request()->header(), true) . PHP_EOL, FILE_APPEND); file_put_contents(storage_path(\'logs/SERVER_HeaderReal.txt\'), \'string\' . var_export(request()->header(\'ORIGIN\'), true) . PHP_EOL, FILE_APPEND); $origin = isset($_SERVER[\'HTTP_ORIGIN\'])? $_SERVER[\'HTTP_ORIGIN\'] : \'\'; $allow_origin = Config::get(\'app.allow_origin\'); $allow_origin_dynamic = Config::get(\'app.allow_origin_dynamic\'); $allowOrigin = false; if ( in_array( $origin, $allow_origin )) { $allowOrigin = true; } else { foreach ( $allow_origin_dynamic as $item ) { if ( strpos( $origin, $item ) !== false ) { $allowOrigin = true; break; } } } if ( $allowOrigin ) { header(\'Access-Control-Allow-Origin: \'.$origin); header(\'Access-Control-Allow-Methods:POST,GET,OPTIONS,PUT,DELETE\'); header(\'Access-Control-Allow-Headers:x-requested-with,content-type,token\'); header(\'Access-Control-Allow-Credentials:true\'); } return $next($request); /* return $next($request)-> header(\'Access-Control-Allow-Origin\', \'*\') -> header(\'Access-Control-Allow-Methods\', \'POST,GET,OPTIONS,PUT,DELETE\') -> header(\'Access-Control-Allow-Headers\', \'Content-Type,Accept,Authorization,X-Requested-With\');*/ } }
5、上面注册的api中间件绑定到t-local的api/wechat/xxx路由上,从local域名发起访问t-local域名,发现get请求也成功返回了json数据
返回的json数据:数据正确返回了,至于返回的是什么,这已经不重要了,不是吗?!!
6、至此,则完成了laravel5 处理ajax 携带自定义header头Token,并发起的跨域CORS的复杂请求。