Skip to content

Instantly share code, notes, and snippets.

@enygma
Created October 20, 2015 19:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save enygma/0d37f30302ec8b3ba1ba to your computer and use it in GitHub Desktop.
Save enygma/0d37f30302ec8b3ba1ba to your computer and use it in GitHub Desktop.
Laravel provider to introduce "@allows" and "@Denies" into Blade templates
<?php
namespace App\Providers;
use Blade;
use Illuminate\Support\ServiceProvider;
class PropAuthBladeServiceProvider extends ServiceProvider
{
/**
* Boot the provider and register our Blade extension
*/
public function boot()
{
Blade::extend(function($value, $obj) {
// See if we need an enforcer
if (strpos($value, '@allows') === false && strpos('@denies', $value) === false) {
return $value;
}
// Add the enforcer to the page
$value = '<?php $enforcer = \App::make("policies"); ?>'.$value;
// Handle @allows and @denies
$value = $this->parse($value);
return $value;
});
}
/**
* Parse the template and perform replacements for allows/denies
*
* @param string $value Template contents
* @return string Modified template contents
*/
protected function parse($value)
{
// Replace the check starts
preg_match_all('/(@(allows|denies)\()(.*?)(\))/ms', $value, $matches);
foreach ($matches[0] as $index => $match) {
$params = $matches[3][$index];
$type = $matches[2][$index];
// if we have a comma, we have extra info
$replaceWith = (strpos($params, ',') !== false)
? $this->replaceComplex($type, $params) : $this->replaceSimple($type, $params);
$value = str_replace($match, $replaceWith, $value);
// Replace the end of the check
$value = str_replace('@end'.$type, '<?php endif; ?>', $value);
}
return $value;
}
/**
* Perform a simple replacement on the type (allows/denies) check
*
* @param string $type Type of check (allows, denies)
* @param string $params Parameter string
* @return string Formatted replacement string
*/
protected function replaceSimple($type, $params)
{
return '<?php if ($enforcer->'.$type.'('.$params.', \Auth::user()) === true): ?>';
}
/**
* Perform a more complex replacement on the type (allows/denies) check
* This usually means that they have additional parameters on the check
*
* @param string $type Type of check (allows, denies)
* @param string $params Parameter string
* @return string Formatted replacement string
*/
protected function replaceComplex($type, $params)
{
$params = array_map(function($value) {
return trim($value);
}, explode(',', $params));
$policyName = array_shift($params);
$addl = '['.implode(',', $params).']';
$replaceWith = '<?php if ($enforcer->'.$type.'('.$policyName.', \Auth::user(), '.$addl.') === true) : ?>';
return $replaceWith;
}
public function register()
{
// nothing to see, move along
}
}
@enygma
Copy link
Author

enygma commented Oct 20, 2015

This would be used like:

@allows('can-edit')
   I can edit!
@endallows

@denies('can-delete', $post)
   I cannot delete!
@enddenies

Where can-edit and can-delete are policies, in this case, defined in a PolicyServiceProvider (http://websec.io/2015/10/07/Security-Policy-Evaluation-Laravel-PropAuth.html)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment