Laravel 系列 (一)

助手函数

1
php artisan make:provider HelperServiceProvider
1
2
3
4
5
# config/app.php
...
App\Providers\HelperServiceProvider::class,
App\Providers\AppServiceProvider::class,
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class HelperServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* @return void
*/
public function register()
{
//
}

/**
* Bootstrap services.
*
* @return void
*/
public function boot()
{
foreach (glob(app_path('Helpers') . '/*.php') as $helperFile) {
require_once $helperFile;
}
}
}

nwidart/laravel-modules - 模块化管理

1
2
3
4
5
6
7
8
9
10
composer require "nwidart/laravel-modules:^6.0"

php artisan vendor:publish --provider="Nwidart\Modules\LaravelModulesServiceProvider"

# config/modules.php 配置
# 1.修改命名空间 (Modules => App\Modules)
'namespace' => 'App\Modules'
'modules' => base_path('app/Modules'),
# 2.重命名 resource (Transformers => Http/Resources)
'resource' => ['path' => 'Http/Resources', 'generate' => false]

laravel/passport

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
<?php

namespace App\Traits;

use Exception;
use Error;
use TypeError;
use DateTimeImmutable;
use Psr\Http\Message\ResponseInterface;
use Laravel\Passport\Passport;
use Laminas\Diactoros\Response as Psr7Response;
use Laravel\Passport\Bridge\{
Client,
AccessToken,
AccessTokenRepository,
RefreshTokenRepository
};
use League\OAuth2\Server\CryptKey;
use League\OAuth2\Server\Entities\{AccessTokenEntityInterface, RefreshTokenEntityInterface};
use League\OAuth2\Server\ResponseTypes\{ResponseTypeInterface, AbstractResponseType, BearerTokenResponse};
use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;
use League\OAuth2\Server\Exception\OAuthServerException;

trait PassportToken
{
/**
* @var CryptKey
*/
protected $privateKey;

/**
* @param string $userIdentifier
* @param int $clientId
* @param bool $ouput
*
* @return array|null|ResponseInterface
* @throws OAuthServerException|UniqueTokenIdentifierConstraintViolationException
*/
protected function getBearerTokenByUser(string $userIdentifier, int $clientId = 0, bool $ouput = false)
{
$this->makeCryptKey('private');
$accessToken = $this->issueAccessToken($userIdentifier, $clientId);
$refreshToken = $this->issueRefreshToken($accessToken);

$tokenResponse = $this->getResponse();
$tokenResponse->setAccessToken($accessToken);
$tokenResponse->setRefreshToken($refreshToken);
$response = $tokenResponse->generateHttpResponse(new Psr7Response());

if (!$ouput) {
return json_decode($response->getBody()->__toString(), true);
}

return $response;
}

/**
* Issue an access token.
*
* @param string $userIdentifier
* @param string $clientId
*
* @return AccessTokenEntityInterface
* @throws OAuthServerException|UniqueTokenIdentifierConstraintViolationException
*/
private function issueAccessToken(string $userIdentifier, string $clientId)
{
// 这里 $clientId 必须是 oauth_clients 表存在的记录, 不然生成的 access_token 无法通过校验
// 参考源码 vendor\laravel\passport\src\Bridge\ClientRepository.php - validateClient
$client = new Client($clientId, null, null);
$accessToken = new AccessToken($userIdentifier, [], $client);
$accessToken->setExpiryDateTime((new DateTimeImmutable())->add(Passport::tokensExpireIn()));
$accessToken->setPrivateKey($this->privateKey);

/** @var AccessTokenRepository $accessTokenRepository */
$accessTokenRepository = app(AccessTokenRepository::class);

$maxGenerationAttempts = 10;
while ($maxGenerationAttempts-- > 0) {
$accessToken->setIdentifier($this->generateUniqueIdentifier());
try {
$accessTokenRepository->persistNewAccessToken($accessToken);

return $accessToken;
} catch (UniqueTokenIdentifierConstraintViolationException $e) {
if ($maxGenerationAttempts === 0) {
throw $e;
}
}
}
}

/**
* Issue an refresh token.
*
* @param AccessTokenEntityInterface $accessToken
*
* @return RefreshTokenEntityInterface
* @throws OAuthServerException|UniqueTokenIdentifierConstraintViolationException
*/
private function issueRefreshToken(AccessTokenEntityInterface $accessToken)
{
/** @var RefreshTokenRepository $refreshTokenRepository */
$refreshTokenRepository = app(RefreshTokenRepository::class);
$refreshToken = $refreshTokenRepository->getNewRefreshToken();
$refreshToken->setExpiryDateTime((new DateTimeImmutable())->add(Passport::refreshTokensExpireIn()));
$refreshToken->setAccessToken($accessToken);

$maxGenerationAttempts = 10;
while ($maxGenerationAttempts-- > 0) {
$refreshToken->setIdentifier($this->generateUniqueIdentifier());
try {
$refreshTokenRepository->persistNewRefreshToken($refreshToken);

return $refreshToken;
} catch (UniqueTokenIdentifierConstraintViolationException $e) {
if ($maxGenerationAttempts === 0) {
throw $e;
}
}
}
}

/**
* Get the token type that grants will return in the HTTP response.
*
* @return ResponseTypeInterface
*/
private function getResponse()
{
$responseType = new BearerTokenResponse();
if ($responseType instanceof AbstractResponseType) {
$responseType->setPrivateKey($this->privateKey);
}

$responseType->setEncryptionKey(app('encrypter')->getKey());

return $responseType;
}

/**
* Create a CryptKey instance without permissions check.
*
* @param string $type
*/
private function makeCryptKey($type)
{
$key = str_replace('\\n', "\n", config('passport.' . $type . '_key'));
if (!$key) {
$key = 'file://' . Passport::keyPath('oauth-' . $type . '.key');
}

$this->privateKey = new CryptKey($key, null, false);
}

/**
* Generate a new unique identifier.
*
* @param int $length
*
* @return string
* @throws OAuthServerException
*/
private function generateUniqueIdentifier($length = 40)
{
try {
return \bin2hex(\random_bytes($length));
// @codeCoverageIgnoreStart
} catch (TypeError $e) {
throw OAuthServerException::serverError('An unexpected error has occurred', $e);
} catch (Error $e) {
throw OAuthServerException::serverError('An unexpected error has occurred', $e);
} catch (Exception $e) {
// If you get this message, the CSPRNG failed hard.
throw OAuthServerException::serverError('Could not generate a random string', $e);
}
// @codeCoverageIgnoreEnd
}
}
0%