标签 PHP 下的文章

基于 Laravel + Dingo api + JWT + laravel-admin 的基础项目
基于 rest api 完成了注册登录等接口,修改后直接使用

代码下载

启动新项目直接使用节省时间
前后台和接口独立域名

版本:

  • Laravel 5.7.13
  • Dingo api 2.0.0-alpha2
  • JWT rc.3
  • laravel-admin 1.6.7

以下所有例子都是使用 lvbegin.com 域名

接口地址: http://api.lvbegin.com
管理端:http://admin.lvbegin.com
门户:http://www.lvbegin.com

开发环境部署
$ composer install
$ cp .env.example .env

根据实际情况修改设置,特别是数据库和REDIS,还有下面两个

ADMIN_DOMAIN=[admin.lvbegin.com](http://admin.lvbegin.com)
API_DOMAIN=[api.lvbegin.com](http://api.lvbegin.com)

继续执行下面命令

$ php artisan key:generate
$ php artisan admin:install
$ php artisan vendor:publish --provider="Encore\Admin\AdminServiceProvider"
$ php artisan jwt:secret
$ php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
$ php artisan vendor:publish --provider="Dingo\Api\Provider\LaravelServiceProvider"

以上执行完毕,并且修改了虚拟主机配置后可以通过浏览器打开

http://admin.lvbegin.com 测试管理端,账号和密码: admin

http://api.lvbegin.com 接口需要通过 postman 测试

接口列表:
php artisan api:routes

用户验证接口

测试的时候记得先调用注册接口注册一个用户先

虚拟主机参考
server {
    listen 80;
    server_name api.lvbegin.com admin.lvbegin.com www.lvbegin.com;
    index index.php index.html index.htm;
    root /data/www/laravel-beginning/public; # default Laravel's entry point for all requests
    set_real_ip_from 10.104.17.235;
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;
    location / {
        # try to serve file directly, fallback to index.php
        try_files $uri /index.php?$args;
    }
    location ~ \.php$ {
        fastcgi_index index.php;
        fastcgi_pass 127.0.0.1:9000; # address of a fastCGI server
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        include fastcgi_params;
    }
}
截图

管理端

管理端

POSTMAN 调试

参考

找到的例子是一个Blog ,由于作者是法国人,而且文档是介绍在DOCKER下跑的,我在MAC上尝试掉进了不少坑
项目地址:
https://github.com/guillaumebriday/laravel-blog

安装好:composer & node & MySQL & PHP扩展 pcntl

$ git clone https://github.com/guillaumebriday/laravel-blog.git
$ cd laravel-blog
$ cp .env.example .env
$ composer install
$ php artisan key:generate
$ php artisan vendor:publish --provider="Laravel\Horizon\HorizonServiceProvider"
$ php artisan storage:link
$ php artisan migrate --seed
$ npm install
$ npm run dev
$ php artisan serve

我本地没有 Redis 要做以下修改

"message": "php_network_getaddresses: getaddrinfo failed: nodename nor servname provided, or not known [tcp://redis:6379]",

.env 中的

QUEUE_CONNECTION = redis

应该是写错了是下面这个才对,同时改为用 databases

QUEUE_DRIVER = databases
BROADCAST_DRIVER = pusher 

pusher 依赖 Redis 改成 log

BROADCAST_DRIVER = log

以上一路没出错的话就恭喜,可以访问 http://localhost:8000
账号密码:darthvader@deathstar.ds / 4nak1n

laravel-blog-a.png
laravel-blog-b.png
laravel-blog-c.png

注意:修改配置后必须清缓存

php artisan config:clear

并且重启http服务

php artisan serve

前阵子受到羊毛党的报复,对我们短信接口发起攻击。
分析LOG发现有几千个IP,我就不相信他有这么多肉鸡……怀疑我们获取到的IP是伪造不真实的IP。
IP有这么好伪造吗?那就视乎你怎么获取IP了,看THINKPHP获取IP的代码,主要是通过下面的环境变量获取:
REMOTE_ADDR
HTTP_X_FORWARDED_FOR
HTTP_CLIENT_IP

/**
 * 获取客户端IP地址
 * @param integer   $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
 * @param boolean   $adv 是否进行高级模式获取(有可能被伪装)
 * @return mixed
 */
public function ip($type = 0, $adv = false)
{
    $type = $type ? 1 : 0;
    static $ip = null;
    if (null !== $ip) {
        return $ip[$type];
    }

    if ($adv) {
        if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
            $pos = array_search('unknown', $arr);
            if (false !== $pos) {
                unset($arr[$pos]);
            }
            $ip = trim(current($arr));
        } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        } elseif (isset($_SERVER['REMOTE_ADDR'])) {
            $ip = $_SERVER['REMOTE_ADDR'];
        }
    } elseif (isset($_SERVER['REMOTE_ADDR'])) {
        $ip = $_SERVER['REMOTE_ADDR'];
    }
    // IP地址合法验证
    $long = sprintf("%u", ip2long($ip));
    $ip   = $long ? array($ip, $long) : array('0.0.0.0', 0);
    return $ip[$type];
}

我们代码里面都是通过 $this->request->ip() 获取IP的……可能我们被羊毛骗了

再看看下面这个代码
HTTP_X_FORWARDED_FOR 和 HTTP_CLIENT_IP
伪造就是这么容易,这就是XFF欺骗

$url = 'http://www.fake.com/index.php';
// 参数
$data_string = '';
$URL_Info = parse_url($url);
$request = '';
if (!isset($URL_Info["port"])) {
    $URL_Info["port"] = 80;
}
$request.="POST ".$URL_Info["path"]." HTTP/1.1\n";
$request.="Host: ".$URL_Info["host"]."\n";
$request.="Referer: ".$URL_Info["host"]."\n";
$request.="Content-type: application/x-www-form-urlencoded\n";
// HTTP_X_FORWARDED_FOR 的值,可以随心所欲
$request.="X-Forwarded-For:192.168.1.4\n";
// HTTP_CLIENT_IP 的值,可以随心所欲
$request.="client_ip:192.168.1.5\n";
$request.="Content-length: ".strlen($data_string)."\n";
$request.="Connection: close\n";
$request.="\n";
$request.=$data_string."\n";
$fp = fsockopen($URL_Info["host"], $URL_Info["port"]);

fputs($fp, $request);
fclose($fp);

了解到通过REMOTE_ADDR获取的IP是不能伪造,不过我们生产环境用了反向代理,架构类似下图

d83868e7b403360a546824d0a1b808f2.png

反向代理每个虚拟主机配置都加了这样的配置

proxy_set_header Host $host;
proxy_set_header X-Real-Ip  $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

这样是可以转发 HTTP_X_FORWARDED_FOR 到RS服务器,不过 REMOTE_ADDR 还是代理的IP,不知道

proxy_set_header X-Real-Ip  $remote_addr;

这个作用是什么,看着不是把 REMOTE_ADDR 转发到RS服务器,当时为了快速解决我把

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 

改成

proxy_set_header X-Forwarded-For $remote_addr;

然后这样获取
$this->request->ip(0, true)

set_real_ip_from 10.10.10.10;
real_ip_header X-Forwarded-For;

PHP中$_SERVER没有走代理访问的时候是没有下面两个值的

[HTTP_X_FORWARDED_FOR] => 27.46.8.255
[HTTP_X_REAL_IP] => 27.46.8.255
[HTTP_X_FORWARDED_FOR] => 192.168.1.4, 27.46.8.255
[HTTP_X_REAL_IP] => 27.46.8.255

未完待续....