简易laravel路由权限开关(附黑名单防刷)
首先还是介绍一下存储吧,mysql,由于数据量不会很多,至于需不需要用到no-sql缓存,就看大家具体项目的抉择了。生成简单的一个迁移文件,充当路由权限表,主要通过路由的别名充当唯一键。
代码 :
<?phpuse AppModelsV1SystemAppRouterConfig;
use IlluminateSupportFacadesSchema;
use IlluminateDatabaseSchemaBlueprint;
use IlluminateDatabaseMigrationsMigration;
class CreateAppRouterConfigsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create(AppRouterConfig::TABLE, function (Blueprint $table) {
$table->increments("id");
$table->string("name",50)->unique()->comment("名称");
$table->string("uri",100)->comment("路由");
$table->string("methods",30)->nullable()->comment("方法");
$table->string("black_ips",100)->nullable()->comment("ip黑名单");
$table->string("black_users",200)->nullable()->comment("用户黑名单");
$table->string("black_devices",200)->nullable()->comment("设备黑名单");
$table->string("tips_message",200)->nullable()->comment("提示语");
$table->tinyInteger("status")->default(AppRouterConfig::STATUS_ABLE)->comment("状态");
$table->timestamps();
});
IlluminateSupportFacadesDB::statement("ALTER TABLE ".AppRouterConfig::TABLE." comment "路由权限表"");
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists(AppRouterConfig::TABLE);
}
}
表结构确定好之后,我们考虑一下数据填充。
这里也是集成到laravel 的 artisan脚本生成工具之中,每次路由有更新需要用到权限的时候,执行一下脚本即可。
php artisan cron:init-router-access
command脚本入口文件,这个就不具体讲了,不同的项目会有不同的规范。
<?phpnamespace AppConsoleCommandsCron;
use AppServicesCardCardService;
use AppServicesCronRouterAccessService;
use IlluminateConsoleCommand;
class InitRouterAccess extends Command
{
protected $service;
protected $signature = "cron:init-router-access";
protected $description = "初始化路由权限";
public function __construct(RouterAccessService $service)
{
parent::__construct();
$this->service = $service;
}
/**
* @throws Throwable
*/
public function handle()
{
//你要执行的任务
$this->service->run();
}
}
其次实现方式我们用常规的中间件形式,主要的处理逻辑在Service文件中,这里有三个主要函数,
<?php/** * User: Freeze* Date: 2020/03/31 * Time: 19:58 */namespace AppServicesCron;
use AppModelsV1SystemAppRouterConfig;
use IlluminateSupportFacadesDB;
class RouterAccessService
{
public $message;
/**
* @return mixed
*/
public function getMessage()
{
return $this->message;
}
/**
* @param mixed $message
*/
public function setMessage($message): void
{
$this->message = $message;
}
/**
* 验证路由权限
* @param $name
* @return bool
*/
public function check( $request, $name)
{
$dbRouter = AppRouterConfig::query()->where("name", $name)->first();
if ($dbRouter && $dbRouter->status == AppRouterConfig::STATUS_DIABLE) {
$this->setMessage($dbRouter->tips_message ?: "该请求服务已停用");
return false;
}
if ($dbRouter && $dbRouter->black_ips && in_array($request->ip(), explode(",", $dbRouter->black_ips))) {
$this->setMessage("请求拒绝,您的IP已被识别为非法操作!");
return false;
}
if ($dbRouter && $dbRouter->black_devices) {
$device_no = $request->header("device_no");
if ($device_no && in_array($device_no, explode(",", $dbRouter->black_devices))) {
$this->setMessage("请求拒绝,您的账号已被识别为非法操作!");
return false;
}
}
return true;
}
/**
* 根据用户登录态验证路由权限
* @param $name
* @return bool
*/
public function checkAuth( $request, $name)
{
$dbRouter = AppRouterConfig::query()->where("name", $name)->first();
if ($dbRouter && $dbRouter->black_users && $request->user() && in_array($request->user()->id, explode(",", $dbRouter->black_users))) {
$this->setMessage("请求拒绝,您的账号已被识别为非法操作!");
return false;
}
return true;
}
//初始化路由权限,写入数据表
public function run()
{
try {
DB::transaction(function () {
$routers = app("router")->getRoutes()->getRoutesByName();
foreach ($routers as $name => $router) {
AppRouterConfig::query()->updateOrCreate([
"name" => $name,
], [
"uri" => $router->uri,
"methods" => implode(",", $router->methods)
]);
}
});
} catch (Exception $exception) {
logger("RouteAccess:" . $exception->getMessage());
echo $exception->getMessage();
}
}
}
1. run是每次刷新路由表的数据跑的脚本执行的,基础的sql操作,其中路由别名(name)充当唯一键的作用。
简单的打印个例子
2.check方法就是我们的开关和黑名单过滤功能的体现。
代码也是通俗易懂,status决定该路由的开关,black_ips决定ip黑名单的过滤,black_devices决定设备号的过滤,当然还有black_users针对已登录用户的id的过滤(由于这个用户id的值必须要等到jwt登录态校验处理完之后,才能拿到,故单独开了一个中间件放在jwt后面,做这个black_users的过滤处理),大家可以根据自己的需要补充一下其他维度的黑名单处理。
中间件代码:
全局过滤
<?phpnamespace AppHttpMiddlewareApiV1Common;
use AppExceptionsCheckSignException;
use AppExceptionsInvalidRequestException;
use AppServicesActivityGashaponService;
use AppServicesCronRouterAccessService;
use CarbonCarbon;
use Closure;
use IlluminateSupportFacadesRedis;
class RouterAccessMiddleware
{
public $accessService;
public function __construct(RouterAccessService $accessService)
{
$this->accessService = $accessService;
}
/**
* 验证签名中间件
* @param $request
* @param Closure $next
* @return mixed
* @throws CheckSignException
* @throws InvalidRequestException
*/
public function handle($request, Closure $next)
{
$route_name = $request->route()->getName();
if (!$this->accessService->check($request,$route_name)) throw new InvalidRequestException($this->accessService->getMessage());
return $next($request);
}
}
3. 需要登录态获取用户id过滤
<?phpnamespace AppHttpMiddlewareApiV1Common;
use AppExceptionsCheckSignException;
use AppExceptionsInvalidRequestException;
use AppServicesActivityGashaponService;
use AppServicesCronRouterAccessService;
use CarbonCarbon;
use Closure;
use IlluminateSupportFacadesRedis;
class RouterAuthAccessMiddleware
{
public $accessService;
public function __construct(RouterAccessService $accessService)
{
$this->accessService = $accessService;
}
/**
* 验证签名中间件
* @param $request
* @param Closure $next
* @return mixed
* @throws CheckSignException
* @throws InvalidRequestException
*/
public function handle($request, Closure $next)
{
$route_name = $request->route()->getName();
if (!$this->accessService->checkAuth($request,$route_name)) throw new InvalidRequestException($this->accessService->getMessage());
return $next($request);
}
}
到这里,一个简易的路由权限控制已经做好了,希望能帮到大家。
最后附上数据表中的一些数据情况作为说明。
以上是 简易laravel路由权限开关(附黑名单防刷) 的全部内容, 来源链接: utcz.com/z/514953.html