【laravel】- 用户认证
Mai Miao 3/20/2022 laravel
基于laravel-8,使用Guard创建一个自定义认证系统,redis存储token
# 配置 Auth guard
在 `config/auth.php` 文件中 更新如下
<?php
return [
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'user_token',
'provider' => 'cache_user',
],
'admin' => [
'driver' => 'user_token',
'provider' => 'cache_user',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'cache_user' => [
'driver' => 'cache_user',
'model' => App\Models\User::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
'password_timeout' => 10800,
];
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
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
# 配置用户模型
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
protected $table = 'users';
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 创建用户token守护器
文件位置:`app/Auth/Guard/CustomTokenGuard.php`
<?php
namespace App\Auth\Guard;
use App\Constants\RedisConst;
use Illuminate\Auth\TokenGuard;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redis;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
class CustomTokenGuard extends TokenGuard
{
public function user()
{
$this->inputKey = 'token';
$this->storageKey = 'id';
if (!is_null($this->user)) {
return $this->user;
}
$user = null;
$token = $this->getTokenForRequest();
if (!$token) throw new UnauthorizedHttpException('user_token', '未包含token!');
if (!$tokenKey = Redis::get('user_token' . $token)) throw new UnauthorizedHttpException('user_token', 'token不正确!');
$userId = explode(':', $tokenKey)[1];
$user = $this->provider->retrieveByCredentials(
[$this->storageKey => $userId]
);
return $this->user = $user;
}
/**
* Get the token for the current request.
*
* @return string
*/
public function getTokenForRequest()
{
return $this->request->header($this->inputKey);
}
}
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
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
# 配置用户守护器
文件位置:`app/Auth/Guard/CacheUserProvider.php`
<?php
namespace App\Auth\UserProvider;
use Illuminate\Auth\EloquentUserProvider;
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
class CacheUserProvider extends EloquentUserProvider
{
public function __construct(HasherContract $hasher, $model)
{
parent::__construct($hasher, $model);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 注册用户守护实例
更新注册 `app/Providers/AuthServiceProvider.php`
<?php
namespace App\Providers;
use App\Auth\Guard\CustomTokenGuard;
use App\Auth\UserProvider\CacheUserProvider;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Gate;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array<class-string, class-string>
*/
protected $policies = [
// 'App\Models\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
// 注册
$auth = Auth::provider('cache_user', function ($app, $config) {
return new CacheUserProvider($app['hash'], $config['model']);
});
$auth->extend('user_token', function ($app, $name, $config) use ($auth) {
$guard = new CustomTokenGuard(
$auth->createUserProvider($config['provider'] ?? null),
$app['request']
);
$app->refresh('request', $guard, 'setRequest');
return $guard;
});
}
}
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
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
# 进行登录设计
路由地址 `routes/admin.php`
Route::post('authorizations', [AuthorizationsController::class, 'login']);
1
<?php
namespace App\Http\Controllers\Admin;
use App\Constants\ExceptionConst;
use App\Exceptions\InvalidRequestException;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redis;
class AuthorizationsController extends Controller
{
public function login(Request $request)
{
$account = $request->account;
$password = $request->password;
$user = User::where('account', $account)->first();
if (empty($user->password) || $this->transformPassword($password) !== $user->password) return response(['status' => -1, 'msg' => '账号或者密码错误!']);
// 生成 token
$userToken = $this->generateUserToken($user->id);
return $this->success($userToken);
}
private function generateUserToken($reguserId)
{
$userToken = sha1($reguserId . time());
Redis::set('user_token' . $userToken, 'reguser:' . $reguserId, 'EX', 604800); // 一周
Redis::sAdd('reguser:usertokens:' . $reguserId, 'user?_token' . $userToken);
return $userToken;
}
}
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
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
示例如下
# 检验是否守护成功
接口文件routes/api.php
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use \App\Http\Controllers\Api\TestController;
Route::group(['middleware' => ['auth:api']], function () {
Route::prefix('test')->group(function () {
Route::get('/', [TestController::class, 'ApiTest']); // 测试
});
});
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
控制器内容
<?php
namespace App\Http\Controllers\Api;
use \App\Http\Controllers\Api\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class TestController extends Controller
{
public function ApiTest(Request $request)
{
$userId = Auth::id();
$user = Auth::user();
return response(['status' => 0, 'msg' => '', 'result' => ['user_id' => $userId, 'user' => $user]]);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
注意上面有抛出UnauthorizedHttpException异常,我们稍作处理去接管这个异常信息,为了友好的输出错误信息
更新app/Exceptions/Handler.php
如下:
public function render($request, Throwable $e)
{
// 用户认证的异常
if ($e instanceof UnauthorizedHttpException) {
return \response(['status' => 1, 'msg' => $e->getMessage()])
->setStatusCode(Response::HTTP_UNAUTHORIZED);
}
return parent::render($request, $e); // TODO: Change the autogenerated stub
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
当未包含token或者token错误输出如下: