Laravel 通过 cookie 实现基于 session 的单点登录
单点登录说明#
单点登录(Single Sign On),简称为 SSO,意思是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的其它应用系统。一般常用于同一家公司的不同子系统之间的登录认证。
需要插件#
// passport
composer require laravel/passport
// predis
composer require predis/predis
首先我们创建三个项目#
composer create-project --prefer-dist laravel/laravel login.sso.test
composer create-project --prefer-dist laravel/laravel home.sso.test
composer create-project --prefer-dist laravel/laravel my.sso.test
env 配置#
APP_KEY=***
DB_CONNECTION=mysql
DB_HOST=192.168.10.10
DB_PORT=3306
DB_DATABASE=sso
DB_USERNAME=homestead
DB_PASSWORD=secret
BROADCAST_DRIVER=log
CACHE_DRIVER=redis
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis
SESSION_LIFETIME=120
SESSION_DOMAIN=.sso.test
SESSION_DOMAIN
我们在这个 env 新增了这个配置 是为了设置 config/session.php
中配置项 domail
设置 Cookie
域名
三个项目的 APP_KEY
需要设置为一样否者不行
登录认证中心#
安装扩展包#
composer require laravel/passport
composer require predis/predis
执行数据库迁移#
php artisan migrate
运行 artisan
命令#
php artisan passport:install
安装 laravel 自带 认证中心#
composer require laravel/ui
npm install && npm run dev
// 会提示创建页面 不需要的页面可以不创建
composer require laravel/ui
config/auth.php
配置#
guards = [
...
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
]
配置中间件#
protected $middlewareGroups = [
'web' => [
...
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],
'api' => [
...
'throttle:60,1',
'bindings',
]
],
配置路由 routes/api.php
#
// 为了方便测试 取消 token验证
Laravel\Passport\Passport::$ignoreCsrfToken = true;
Route::middleware('auth:api')->group(function () {
Route::get('/user/{id}', function ($id) {
return \App\User::find($id);
});
});
登录认证 中心项目完成
home.sso.test
项目#
安装扩展包#
composer require laravel/passport
composer require predis/predis
安装 laravel
自带认证中心#
composer require laravel/ui
npm install && npm run dev
// 会提示创建页面 不需要的页面可以不创建
// 子系统不需要登录注册找回密码等页面 所以 全部选择 no
composer require laravel/ui
自定义 Provider
#
我们需要自定一个 SsoUserProvider 来实现从主系统获取用户信息,在 app
目录下创建一个 Extensions
目录 创建SsoUserProvider
// 创建文件夹
mkdir Extensions
// 进入目录
cd Extensions
// 创建文件
touch SsoUserProvider.php
SsoUserProvider.php
代码#
<?php
namespace App\Exceptions;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
use Illuminate\Auth\EloquentUserProvider;
class SsoUserProvider extends EloquentUserProvider
{
public function retrieveById($identifier)
{
/**
* 确保百分之百有 laravel_token 如果没有继续去登录
*/
if (isset($_COOKIE['laravel_token']) && $_COOKIE['laravel_token']) {
$http = new Client();
$cookies = CookieJar::fromArray(
[
'laravel_token' => $_COOKIE['laravel_token'],
],
'.sso.test'
);
$response = $http->request(
'GET',
'http://login.sso.test/api/user/'.$identifier,
[
'cookies' => $cookies,
]
);
$user = json_decode($response->getBody()->getContents(), true);
$model = $this->createModel();
$model->forceFill($user);
return $model;
} else {
return redirect('http://login.sso.test/login');
}
}
以上域名 可以走 自定义配置文件
这个自定义类中,我们同过 API
接口获取用户信息并返回
然后设置 config/auth.php
的 providers
配置项修改如下#
'users' => [
'driver' => 'sso',
'model' => App\User::class,
],
最后我们在 AuthServiceProvider .php
的 boot
方法注册自定义的 UserProvider
类让它生效#
use Illuminate\Support\Facades\Auth;
use App\Exceptions\SsoUserProvider;
public function boot()
{
...
Auth::provider(
'sso',
function ($app, $config) {
return new SsoUserProvider($app->make('hash'), $config['model']);
}
);
}
然后们修改 app/Http/Controllers/Auth/LoginController.php
将登录重定向到登录系统
public function showLoginForm()
{
return redirect('http://login.sso.test/login');
}
注册 找回密码 同理
退出登录#
我们修改 app/Http/Controllers/Auth/LoginController.php
文件
public function logout(Request $request)
{
$http = new Client();
$cookies = CookieJar::fromArray(
[
// 注意是 laravel_session 不是laravel_token
'laravel_session' => $_COOKIE['laravel_session'],
'XSRF-TOKEN' => $_COOKIE['XSRF-TOKEN'],
],
'.sso.test'
);
$response = $http->request('POST', 'http://login.sso.test/logout', ['cookies' => $cookies]);
if ($response->getStatusCode() == 200) {
$request->session()->invalidate();
return $this->loggedOut($request) ?: redirect('/');
}
abort(500);
}
登录认证中心 主项目#
因为 post 提交需要 _token
这里为了方便 直接在 app/Http/Middleware/VerifyCsrfToken.php
中的 $except
新增退出路由 否者会 419 错误
protected $except = [
'/logout'
];
my.sso.test 同上 即可
欢迎评论 给出意见 及修改
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: