rizalrepo/sso-client

SSO 客户端 OAuth 2.0

安装: 43

依赖项: 0

建议者: 0

安全性: 0

星标: 0

关注者: 2

分支: 0

开放问题: 0

类型:laravel-package

1.3.0 2024-08-22 07:15 UTC

This package is auto-updated.

Last update: 2024-09-22 07:33:18 UTC


README

#安装

composer require rizalrepo/sso-client

配置

使用运行命令发布SSOController

php artisan vendor:publish --tag=sso-config

连接SSO

打开config/sso.php并根据自己的喜好调整配置

return [
    'callbackUrl' => "http://127.0.0.1:8000/callback",
    'serverUrl' => "http://127.0.0.1:8081",
    'clientId' => "f9c2bbad-c06d-4028-9786-213c9113ddbb",
    'clientSecret' => "1zJyzTcLmL05ZzMOnaMI6DfhaY9guJLCKBisH4YS",
];

路由

将代码添加到web.php

Route::controller(SSOController::class)->group(function () {
    Route::get("/", 'ssoPage');
    Route::get("/sso/login", 'getLogin')->name("sso.login");
    Route::get("/callback", 'getCallback')->name("sso.callback");
    Route::get("/sso/connect", 'connectUser')->name("sso.connect");

    Route::middleware('auth')->group(function () {
        Route::get("/sso/logout", 'logout')->name("sso.logout");
        Route::get("/sso/edit-password", 'editPassword')->name("sso.edit-password");
        Route::get("/sso/portal", 'portal')->name("sso.portal");
        Route::get("/sso/profile", 'editProfile')->name("sso.profile");
    });
});

使用以下代码修改文件users migration

Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('username')->unique();
    $table->string('phone')->unique();
    $table->char('prodi', 5)->nullable();
    $table->bigInteger('oauth_client_role_id');
    $table->timestamp('email_verified_at')->nullable();
    $table->rememberToken();
    $table->timestamps();
});

中间件设置

  • 对于Laravel 11,添加命令
php artisan make:middleware Authenticate
  • 然后更新以下代码到Middleware/Authenticate.php,并根据您的喜好调整配置
<?php
namespace App\Http\Middleware;

use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Http\Request;

class Authenticate extends Middleware
{
    private function getConfig($configName)
    {
        switch ($configName) {
            case 'serverUrl':
                return "http://127.0.0.1:8000/login";
            default:
                return null;
        }
    }

    protected function redirectTo(Request $request): ?string
    {
        return $request->expectsJson() ? null : $this->getConfig('serverUrl');
    }
}
  • 然后将以下代码复制到文件bootstrap/app.php
$middleware->alias(['auth' => Authenticate::class]);
  • 对于Laravel 10:更新以下代码到Middleware/Authenticate.php,并根据您的喜好调整配置
<?php
namespace App\Http\Middleware;

use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Http\Request;

class Authenticate extends Middleware
{
    private function getConfig($configName)
    {
        switch ($configName) {
            case 'serverUrl':
                return "http://127.0.0.1:8000/login";
            default:
                return null;
        }
    }

    protected function redirectTo(Request $request): ?string
    {
        return $request->expectsJson() ? null : $this->getConfig('serverUrl');
    }
}

视图配置

  • 使用以下代码来显示用户头像、直接访问门户、更新个人资料、编辑密码和注销
{{-- in app blade --}}

<div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
    <img class="b-r-10 avatar-image" src="{{ session('avatar') }}" alt="Logo">
    @if(session()->has('countAccess'))
        @if (session('countAccess') > 1)
            <a class="dropdown-item" href="{{ route('sso.portal') }}">Portal</a>
        @endif
    @endif
    <a href="{{ route('sso.profile') }}" onclick="saveReferrer()"><i class="fas fa-user-edit me-2"></i><span>Edit Profile</span></a>
    <a class="dropdown-item" href="{{ route('sso.edit-password') }}" onclick="saveReferrer()">
        Edit Password
    </a>
    <a class="dropdown-item" href="{{ route('sso.logout') }}"
        onclick="event.preventDefault(); document.getElementById('logout-form').submit();">
        {{ __('Logout') }}
    </a>

    <form id="logout-form" action="{{ route('sso.logout') }}" method="GET" class="d-none">
        @csrf
    </form>
</div>

{{-- previous url config in js.blade --}}

<script>
    function saveReferrer() {
        var previousUrl = document.referrer;
        var previousUrlInput = document.getElementById("previous_url");
        if (previousUrlInput) {
            previousUrlInput.value = previousUrl;
        }
    }
</script>

客户端的用户控制器

  • 用户创建后,将此代码添加到store函数中
$ssoController = new \App\Http\Controllers\SSO\SSOController();
$userArray = [
    'name' => $user->name,
    'username' => $user->username,
    'phone' => $user->phone,
    'oauth_client_role_id' => $user->oauth_client_role_id,
];

$ssoController->createUserOnServer($userArray);
  • 用户更新后,将此代码添加到update函数中
$oldUsername = $user->username; // this code add before update()

$updatedUserArray = [
    'name' => $user->name,
    'username' => $user->username,
    'phone' => $user->phone,
    'old_username' => $oldUsername,
];

$ssoController = new \App\Http\Controllers\SSO\SSOController();
$ssoController->updateUserOnServer($updatedUserArray);
  • 用户删除后,将此代码添加到destroy函数中
$username = $data->username; // this code add before delete()

$ssoController = new \App\Http\Controllers\SSO\SSOController();
$ssoController->deleteUserOnServer($username);

从客户端验证API令牌

  • 使用运行命令创建新的中间件
php artisan make:middleware VerifyApiToken
  • 然后打开文件VerifyApiToken,并用以下代码替换
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class VerifyApiToken
{
    public function handle($request, Closure $next)
    {
        $token = $request->bearerToken();

        if (!$token) {
            Log::warning('No bearer token provided and no access token in session');
            return response()->json(['error' => 'Unauthorized'], 401);
        }

        try {
            $serverUrl = Config::get('sso.serverUrl');
            $response = Http::timeout(5)->withHeaders([
                'Accept' => 'application/json',
                'Authorization' => 'Bearer ' . $token,
            ])->get($serverUrl . '/api/verify-token');

            if ($response->successful()) {
                $request->merge(['sso_user' => $response->json()]);
                return $next($request);
            }

            return response()->json(['error' => 'Invalid token'], 401);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Error verifying token'], 500);
        }
    }
}

  • 为Laravel 10添加中间件别名到Kernel.php,或为Laravel 11添加到bootstrap/app.php
'verify.api.token' => \App\Http\Middleware\VerifyApiToken::class,