Introduction
- The company has implemented a unified account center service using go-zero
- Some project backends built with
dcat-admin
need to authenticate users through this account center, documenting the implementation process
Environment Setup
- Protobuf binary files from https://github.com/protocolbuffers/protobuf/releases
- Follow official documentation for installation: https://cloud.google.com/php/grpc?hl=zh-cn#windows
- For Windows: Download corresponding PHP version DLL from https://pecl.php.net/package/grpc
- Install packages:
composer require "grpc/grpc:^1.38" composer require "google/protobuf:^3.17"
- For Docker (using mlocati/docker-php-extension-installer):
RUN install-php-extensions grpc
- Generate PHP gRPC code requires
grpc_php_plugin
:- Official guide: https://github.com/grpc/grpc/blob/v1.58.0/src/php/README.md
- Windows prebuilt: https://github.com/lifenglsf/grpc_for_windows
- Generate PHP classes from proto files and include in project
Implementation Code
Overridden Auth Controller
<?php
namespace App\Admin\Controllers;
use App\Services\AccountRpc;
use Dcat\Admin\Admin;
use Dcat\Admin\Http\Controllers\AuthController as BaseAuthController;
use Dcat\Admin\Models\Administrator;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
class AuthController extends BaseAuthController
{
public function postLogin(Request $request)
{
$username = $request->input('username');
$password = $request->input('password');
$remember = (bool)$request->input('remember', false);
$admin = Administrator::query()->firstOrNew(['username' => $username]);
if ($admin->exists) {
if (!Hash::check($password, $admin->password)) {
return $this->validationErrorsResponse([$this->username() => 'Invalid password']);
}
try {
AccountRpc::me($admin->remember_token);
$this->guard()->login($admin, $remember);
return $this->sendLoginResponse($request);
} catch (\Exception $e) {
Log::error($e);
}
}
try {
$res = AccountRpc::login($username, $password);
} catch (\Exception $e) {
return $this->validationErrorsResponse([$this->username() => 'RPC Error: ' . $e->getMessage()]);
}
$admin->name = $res->getUser()->getNickname();
$admin->password = Hash::make($password);
$admin->remember_token = $res->getSession()->getToken();
$admin->save();
$this->guard()->login($admin, $remember);
return $this->sendLoginResponse($request);
}
public function getLogout(Request $request)
{
$admin = $this->guard()->user();
try {
AccountRpc::logout($admin->remember_token);
} catch (\Exception $e) {
Log::error($e->getMessage());
}
$this->guard()->logout();
$request->session()->invalidate();
$path = admin_url('auth/login');
return $request->pjax()
? "<script>location.href = '$path';</script>"
: redirect($path);
}
}
Account Service Client
<?php
namespace App\Services;
use Account\AccountClient;
use Grpc\ChannelCredentials;
class AccountRpc
{
protected static $client;
public static function login($username, $password)
{
$meta = ['appId' => ['test'], 'groupId' => ['test']];
list($res, $status) = self::client()->Auth(new AuthRequest(), $meta, ['timeout' => 3000000])->wait();
if ($status->code !== 0) {
throw new \Exception($status->details);
}
return $res;
}
public static function client()
{
return self::$client ??= new AccountClient(
config('rpc.account'),
['credentials' => ChannelCredentials::createInsecure()]
);
}
// Other methods (me(), logout()) omitted for brevity
}
Troubleshooting
gRPC Blocking Issue in Production
Add these configurations to Dockerfile when using Laravel-S:
RUN install-php-extensions pcntl redis pdo_mysql zip bcmath gd grpc
RUN echo "grpc.enable_fork_support = 1" >> /usr/local/etc/php/conf.d/docker-php-ext-grpc.ini &&\
echo "grpc.poll_strategy = epoll1" >> /usr/local/etc/php/conf.d/docker-php-ext-grpc.ini
Key points:
- Proper timeout configuration for gRPC calls
- Handle both local user store and remote gRPC authentication
- gRPC client initialization with insecure credentials for testing
- Critical error logging for RPC failures
This implementation enables hybrid authentication that first checks local credentials, then verifies/updates via gRPC, creating local user records when necessary.