-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Optimal SecurityHttp component (#71)
- Loading branch information
Showing
7 changed files
with
330 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
/** | ||
* This file is part of MineAdmin. | ||
* | ||
* @link https://www.mineadmin.com | ||
* @document https://doc.mineadmin.com | ||
* @contact [email protected] | ||
* @license https://github.com/mineadmin/MineAdmin/blob/master/LICENSE | ||
*/ | ||
|
||
namespace Mine\Security\Http\Aspect; | ||
|
||
use Hyperf\Di\Aop\AbstractAspect; | ||
use Hyperf\Di\Aop\ProceedingJoinPoint; | ||
use Mine\Security\Http\Attribute\CurrentUser; | ||
|
||
class CurrentUserAspect extends AbstractAspect | ||
{ | ||
public array $annotations = [ | ||
CurrentUser::class, | ||
]; | ||
|
||
public function process(ProceedingJoinPoint $proceedingJoinPoint) | ||
{ | ||
return $proceedingJoinPoint->process(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
/** | ||
* This file is part of MineAdmin. | ||
* | ||
* @link https://www.mineadmin.com | ||
* @document https://doc.mineadmin.com | ||
* @contact [email protected] | ||
* @license https://github.com/mineadmin/MineAdmin/blob/master/LICENSE | ||
*/ | ||
|
||
namespace Mine\Security\Http\Command; | ||
|
||
use Hyperf\Command\Annotation\Command; | ||
use Hyperf\Command\Command as Base; | ||
use Hyperf\Stringable\Str; | ||
use Symfony\Component\Console\Input\InputOption; | ||
|
||
#[Command] | ||
class GenJwtSecretCommand extends Base | ||
{ | ||
protected ?string $name = 'mine:gen-jwt-secret'; | ||
|
||
public function __invoke() | ||
{ | ||
$secretName = $this->getSecretName(); | ||
$value = $this->generator(); | ||
$envPath = $this->getEnvPath(); | ||
|
||
if (! file_exists($envPath)) { | ||
$this->error('.env file not is exists!'); | ||
return; | ||
} | ||
if (\Mine\Helper\Str::contains(file_get_contents($envPath), $secretName) === false) { | ||
file_put_contents($envPath, "\n{$secretName}={$value}\n", FILE_APPEND); | ||
} else { | ||
file_put_contents($envPath, preg_replace( | ||
"~{$secretName}\\s*=\\s*[^\n]*~", | ||
"{$secretName}=\"{$value}\"", | ||
file_get_contents($envPath) | ||
)); | ||
} | ||
|
||
$this->info('jwt secret generator successfully:' . $value); | ||
} | ||
|
||
public function getSecretName(): string | ||
{ | ||
return Str::upper($this->input->getOption('secret-name')); | ||
} | ||
|
||
public function getEnvPath(): string | ||
{ | ||
return BASE_PATH . '/.env'; | ||
} | ||
|
||
public function generator(): string | ||
{ | ||
return base64_encode(random_bytes(64)); | ||
} | ||
|
||
protected function configure() | ||
{ | ||
$this->setHelp('run "php bin/hyperf.php mine:gen-jwt" create the new jwt secret'); | ||
$this->setDescription('MineAdmin system gen jwt command'); | ||
} | ||
|
||
protected function getOptions(): array | ||
{ | ||
return [ | ||
'secret-name', 'sn', InputOption::VALUE_OPTIONAL, 'The jwt secret name.default:jwt_secret', 'jwt_secret', | ||
]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
/** | ||
* This file is part of MineAdmin. | ||
* | ||
* @link https://www.mineadmin.com | ||
* @document https://doc.mineadmin.com | ||
* @contact [email protected] | ||
* @license https://github.com/mineadmin/MineAdmin/blob/master/LICENSE | ||
*/ | ||
|
||
namespace Mine\Security\Http; | ||
|
||
use Hyperf\Context\Traits\CoroutineProxy; | ||
use Hyperf\Database\Model\Builder; | ||
use Mine\SecurityBundle\Contract\UserInterface; | ||
use Mine\SecurityBundle\Security; | ||
use Psr\Container\ContainerInterface; | ||
|
||
use function Hyperf\Support\call; | ||
|
||
class CurrentUserProxy implements UserInterface | ||
{ | ||
use CoroutineProxy; | ||
|
||
protected string $proxyKey = 'secret.http.proxy'; | ||
|
||
private Security $security; | ||
|
||
public function __construct( | ||
private string $scene, | ||
private ContainerInterface $container | ||
) { | ||
$this->security = $this->container->get(Security::class); | ||
} | ||
|
||
public function __get($name) | ||
{ | ||
return $this->getAttributes()[$name] ?? null; | ||
} | ||
|
||
public function getEntity(): UserInterface | ||
{ | ||
return $this->getSecurity()->getToken()->user($this->scene); | ||
} | ||
|
||
public function getIdentifier(): string | ||
{ | ||
return call([$this->getEntity(), __FUNCTION__]); | ||
} | ||
|
||
public function getIdentifierName(): string | ||
{ | ||
return call([$this->getEntity(), __FUNCTION__]); | ||
} | ||
|
||
public function getRememberToken(): string | ||
{ | ||
return call([$this->getEntity(), __FUNCTION__]); | ||
} | ||
|
||
public function setRememberToken(string $token): void | ||
{ | ||
call([$this->getEntity(), __FUNCTION__], func_get_args()); | ||
} | ||
|
||
public function getRememberTokenName(): string | ||
{ | ||
return call([$this->getEntity(), __FUNCTION__]); | ||
} | ||
|
||
public function getPassword(): string | ||
{ | ||
return call([$this->getEntity(), __FUNCTION__]); | ||
} | ||
|
||
public function setPassword(string $password): void | ||
{ | ||
call([$this->getEntity(), __FUNCTION__]); | ||
} | ||
|
||
public function getSecurityBuilder(): Builder | ||
{ | ||
return call([$this->getEntity(), __FUNCTION__]); | ||
} | ||
|
||
public function setAttribute(string $key, mixed $value) | ||
{ | ||
return call([$this->getEntity(), __FUNCTION__]); | ||
} | ||
|
||
public function getAttributes(): array | ||
{ | ||
return call([$this->getEntity(), __FUNCTION__]); | ||
} | ||
|
||
protected function getSecurity(): Security | ||
{ | ||
return $this->security; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
/** | ||
* This file is part of MineAdmin. | ||
* | ||
* @link https://www.mineadmin.com | ||
* @document https://doc.mineadmin.com | ||
* @contact [email protected] | ||
* @license https://github.com/mineadmin/MineAdmin/blob/master/LICENSE | ||
*/ | ||
|
||
namespace Mine\Security\Http; | ||
|
||
use Hyperf\Context\ApplicationContext; | ||
use Hyperf\Di\Definition\PropertyHandlerManager; | ||
use Hyperf\Di\ReflectionManager; | ||
use Mine\Security\Http\Attribute\CurrentUser; | ||
|
||
class RegisterCurrentUserPropertyHandler | ||
{ | ||
public static bool $registered = false; | ||
|
||
public static function register(): void | ||
{ | ||
if (static::$registered) { | ||
return; | ||
} | ||
PropertyHandlerManager::register(CurrentUser::class, [static::class, 'handle']); | ||
} | ||
|
||
public static function handle($object, $currentClassName, $targetClassName, $property, $annotation): void | ||
{ | ||
if ($annotation instanceof CurrentUser) { | ||
$reflectionProperty = ReflectionManager::reflectProperty($currentClassName, $property); | ||
$container = ApplicationContext::getContainer(); | ||
$reflectionProperty->setValue(new CurrentUserProxy( | ||
$annotation->secret, | ||
$container, | ||
)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
/** | ||
* This file is part of MineAdmin. | ||
* | ||
* @link https://www.mineadmin.com | ||
* @document https://doc.mineadmin.com | ||
* @contact [email protected] | ||
* @license https://github.com/mineadmin/MineAdmin/blob/master/LICENSE | ||
*/ | ||
|
||
namespace Mine\Security\Http\Tests\Cases\Command; | ||
|
||
use Hyperf\Stringable\Str; | ||
use Mine\Security\Http\Command\GenJwtSecretCommand; | ||
use PHPUnit\Framework\TestCase; | ||
use Symfony\Component\Console\Input\Input; | ||
|
||
/** | ||
* @internal | ||
* @coversNothing | ||
*/ | ||
class GenJwtSecretCommandTest extends TestCase | ||
{ | ||
public function testGenerator(): void | ||
{ | ||
$reflection = new \ReflectionClass(GenJwtSecretCommand::class); | ||
$invoke = $reflection->getMethod('generator'); | ||
$this->assertIsString($invoke->invoke(\Mockery::mock(GenJwtSecretCommand::class))); | ||
} | ||
|
||
public function testGetSecretName(): void | ||
{ | ||
$reflection = new \ReflectionClass(GenJwtSecretCommand::class); | ||
$invoke = $reflection->getMethod('getSecretName'); | ||
$instance = $reflection->newInstanceWithoutConstructor(); | ||
$input = \Mockery::mock(Input::class); | ||
$input->allows('getOption')->andReturn('xxx'); | ||
$instance->setInput($input); | ||
$this->assertSame('XXX', $invoke->invoke($instance)); | ||
} | ||
|
||
public function testGetEnvPath(): void | ||
{ | ||
$reflection = new \ReflectionClass(GenJwtSecretCommand::class); | ||
$invoke = $reflection->getMethod('getEnvPath'); | ||
$m = \Mockery::mock(GenJwtSecretCommand::class); | ||
$this->assertSame(BASE_PATH . '/.env', $invoke->invoke($m)); | ||
} | ||
|
||
public function testInvoke(): void | ||
{ | ||
$reflection = new \ReflectionClass(GenJwtSecretCommand::class); | ||
$invoke = $reflection->getMethod('__invoke'); | ||
$m = \Mockery::mock(GenJwtSecretCommand::class); | ||
$m->shouldAllowMockingProtectedMethods(); | ||
$env = sys_get_temp_dir() . '/' . Str::random(32) . '.env'; | ||
file_put_contents($env, "xxx=1\n"); | ||
$m->allows('getEnvPath')->andReturn($env); | ||
$input = \Mockery::mock(Input::class); | ||
$input->allows('getOption')->andReturn('Demo'); | ||
$m->allows('setInput'); | ||
$m->allows('getSecretName')->andReturn('DEMO'); | ||
$m->allows('generator')->andReturn(base64_encode(random_bytes(64))); | ||
$m->allows('info')->andReturnUsing(function ($v) { | ||
echo $v; | ||
}); | ||
$m->setInput($input); | ||
$invoke->invoke($m); | ||
$this->assertTrue(str_contains(file_get_contents($env), 'DEMO')); | ||
} | ||
} |