csrf攻击
csrf发生场景:
用户A在请求网站B时登录时输入了自己的个人信息,网站B生成cookie信息返回给浏览器,用户A此时已成功登录。在用户关闭浏览器界面同时打开了网站C,此时网站C返回了一些攻击型代码发送到网站B。网站B此时会议用户A的身份cookie信息和权限去完成网站C的操作。
laravel防止csrf操作的方式:由框架本身生成一个token值用于验证非GET的请求,laravel自身带有中间件VerifyCsrfToken,我们可以在请求路由中加上其用于验证,也可以设置不需要验证的路由。
我们可以在提交表单中设置如下代码
<input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">
或
{{csrf_filed()}}
当我们设置了需要通过csrf校验而没有设置CsrfToken值时,该请求会返回错误
服务提供者
用于建立服务提供者的指令:
php artisan make:provider RiakServiceProvider
当我们建立好后
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
//
}
需要将该类注册到配置文件app.config的 ‘provider’数组中
容器
我们通过laravel的入口文件可以找到在bootstrap目录下引用的app.php文件
// 普通 http请求
$app->singleton(
Illuminate\Contracts\Http\Kernel::class,
App\Http\Kernel::class
);
// Console
$app->singleton(
Illuminate\Contracts\Console\Kernel::class,
App\Console\Kernel::class
);
$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
App\Exceptions\Handler::class
);
这当中的singleton方法是其中的一种绑定的方法,其核心代码在vendor\laravel\framework\src\Illuminate\Container 该目录下,具体解析方法可以仔细阅读Container.php文件。简单来说laravel通过PHP的反射机制逐层向上查找依赖注入的类,对其进行实例化,与输入的别名进行绑定。在使用app容器实例化时可以通过调用别名的方式直接获取到注册的实例进行引用。
facade 门面
facade是为了更好的使用容器,相当于IOC容器的代理。使其可以不需要每次都去实例化IOC容器来调用注册的类。我们需要在facade类中声明好调用方法。
//返回服务容器绑定的名称
protected static function getFacadeAccessor()
{
return \App\Util\CharUtil::class;
}
这样在我们想要调用已注册在容器中的方法时,我们可以直接引入对应的facade类进行调用。
简单来说我们通过服务提供者向IOC容器中注册类的实例利用别名标注,facade门面对其引用进行了优化使我们可以更方便的调用已注册的方法。
Route
通过之前的了解我们可以知道,laravel框架之所以作为重量级框架是因为在使用前IOC加载了大量的注册过的实例,下面将通过注册服务提供者中的代码展示laravel是如何加载路由所有配置的。
protected $routeMiddleware = [
'oauth' => \Overtrue\LaravelWeChat\Middleware\OAuthAuthenticate::class,
];
protected $middlewareGroups = [];
// 模仿
public function register()
{
// 注册组件路由
$this->registerRoutes();
// 怎么加载config配置文件
$this->mergeConfigFrom(__DIR__.'', "");
// 怎么根据配置文件去加载auth信息
$this->registerRouteMiddleware();
}
public function boot()
{
$this->loadMemberAuthConfig();
}
protected function loadMemberAuthConfig()
{
config(Arr::dot(config('', []), 'auth.'));
}
protected function registerRouteMiddleware()
{
foreach ($this->middlewareGroups as $key => $middleware) {
$this->app['router']->middlewareGroup($key, $middleware);
}
foreach ($this->routeMiddleware as $key => $middleware) {
$this->app['router']->aliasMiddleware($key, $middleware);
}
}
private function registerRoutes()
{
Route::group($this->routeConfiguration(), function () {
$this->loadRoutesFrom(__DIR__.'/../Http/routes.php');
});
}
private function routeConfiguration()
{
return [
'namespace' => '',
// 这是前缀
'prefix' => '',
// 这是中间件
'middleware' => 'web',
];
}
这两个方法是在服务提供者中常用的Register和boot两个方法,用来注册,初始化需要加载的响应组件。
通过上面的例子可以了解到在loadMemberAuthConfig方法中我们将需要配置的参数写入到config配置文件中通过boot方式初始化。在这之前我们设定好中间件将其注册到IOC容器中的路由中间件组中加以使用。
Config
//加载config配置的方法
if ($this->app->runningInConsole()) {
$this->publishes([__DIR__.'/../config' => config_path('wap')], 'laravel-shop-wap-member-config');
}
//publish方法
class ServiceProvider
{
protected function publishes(array $paths, $groups = null)
{
$this->ensurePublishArrayInitialized($class = static::class);
static::$publishes[$class] = array_merge(static::$publishes[$class], $paths);
if (! is_null($groups)) {
foreach ((array) $groups as $group) {
$this->addPublishGroup($group, $paths);
}
}
}
}
能够发现所有的provider方法都集成了 ServiceProvider,我们可以通过该累中的 publishes方法用来加载config配置
Migration
class ServiceProvider
{
protected function loadMigrationsFrom($paths)
{
$this->app->afterResolving('migrator', function ($migrator) use ($paths) {
foreach ((array) $paths as $path) {
$migrator->path($path);
}
});
}
}
加载自己需要的migration文件
class MemberServiceProvide extends ServiceProvider
{
public function register()
{
$this->registerPublishing();
}
public function loadMigrations()
{
if ($this->app->runningInConsole()) {
$this->loadMigrationsFrom(__DIR__.'/../Database/migrations');
}
}
}
Console,Command
class ServiceProvider {
// ...
public function commands($commands)
{
$commands = is_array($commands) ? $commands : func_get_args();
Artisan::starting(function ($artisan) use ($commands) {
$artisan->resolveCommands($commands);
});
}
// ...
}
class MemberServiceProvide extends ServiceProvider {
protected $commands = [
''::class,
];
public function boot(){
//重写该方法
$this->commands($this->commands);
}
}
class Command extends SymfonyCommand
{
public function call($command, array $arguments = [])
{
$arguments['command'] = $command;
return $this->getApplication()->find($command)->run(
$this->createInputFromArguments($arguments), $this->output
);
}
}
class InstallCommand extends Command
{
// 命令的名称
protected $signature = 'wap-member:install';
// 命令的解释
protected $description = '这个是wap下的member组件安装命令';
public function __construct()
{
parent::__construct();
}
public function handle()
{
// call
$this->call('migrate');
$this->call('vendor:publish', [
// 参数表示 => 参数值
"--provider"=>""
]);
// echo '这是测试wap-member的安装命令';
}
}
View
class ServiceProvider
{
protected function loadViewsFrom($path, $namespace)
{
if (is_array($this->app->config['view']['paths'])) {
foreach ($this->app->config['view']['paths'] as $viewPath) {
if (is_dir($appPath = $viewPath.'/vendor/'.$namespace)) {
$this->app['view']->addNamespace($namespace, $appPath);
}
}
}
$this->app['view']->addNamespace($namespace, $path);
}
}
class ShopServiceProvider extends ServiceProvider
{
public function boot()
{
$this->loadViewsFrom(
__DIR__.'/../Resources/views', 'chris'
);
}
}
<?php
namespace Illuminate\View;
class Factory{
public function __construct(EngineResolver $engines, ViewFinderInterface $finder, Dispatcher $events)
{
$this->finder = $finder;
$this->events = $events;
$this->engines = $engines;
$this->share('__env', $this);
}
public function getFinder()
{
return $this->finder;
}
public function addNamespace($namespace, $hints)
{
$this->finder->addNamespace($namespace, $hints);
return $this;
}
}
?>
<?php
namespace Illuminate\View;
class FileViewFinder{
public function addNamespace($namespace, $hints)
{
$hints = (array) $hints;
if (isset($this->hints[$namespace])) {
$hints = array_merge($this->hints[$namespace], $hints);
}
$this->hints[$namespace] = $hints;
}
//页面输出信息
public function getHints()
{
return $this->hints;
}
}
自定义函数
//函数文件
if (! function_exists('shop_asset')) {
function shop_asset($path, $secure = null)
{
return app('url')->asset($path, $secure);
}
}
//composer.json 加载
{
"autoload": {
"files": [
"$path/helpers.php"
],
"psr-4": {
"$alias": "$path"
}
}
}