首页C# 正文

IdentityServer4实战包含PHP客户端

时间: 2022年6月10日 浏览 114

IdentityServer4实战包含PHP客户端

{
"Id": "PHPClient",
"Name": "php客户端",
"Secret": "8c31656b4acb74f15bf0d2378d8be3e7",
"GrantTypes": "implicit",
"Urls": "http://localhost:8090/callback",
"ApiNames": "PClient,Photo,Position"
},
{
"Id": "PHPAPIClient",
"Name": "php客户端API",
"Secret": "8c31656b4acb74f15bf0d2378d8be3e7",
"GrantTypes": "password",
//"AccessTokenLifetime": 180, //过期时间单位秒,默认1800
"Urls": "",
"ApiNames": "PClientAPI,Photo,Position"
},

1、UI登陆模式,首先在认证服务器配置客户端,认证模式为Implicit,其中urls为php里面配置的回调链接。上面json以展示。

2、新建php项目,这里以laravel框架进行介绍,其他框架大同小异。
composer create-project --prefer-dist laravel/laravel PhpHybirdClient
php artisan key:generate
3、引入必须的包,主要有两个一个是openid,一个是jwt。
composer require jumbojett/openid-connect-php
composer require lcobucci/jwt

4、php客户端进行配置登陆,按照ids4认证服务器中的客户端进行配置

namespace App\Http\Controllers;
use App\User;
use Illuminate\Support\Facades\Auth;
use Jumbojett\OpenIDConnectClient;
use Lcobucci\JWT\Parser;
class AuthController extends Controller
{
public function __construct()
{
$this->middleware('guest');
}
public function Login()
{
$oidc = new OpenIDConnectClient('http://localhost:5000',
'PHPClient', '8c31656b4acb74f15bf0d2378d8be3e7');
$oidc->setResponseTypes(array('id_token'));
$oidc->setRedirectURL('http://localhost:8090/callback'); //设置项目callbackurl
$oidc->addScope(array('openid profile Photo Position'));
$oidc->setAllowImplicitFlow(true);
$oidc->addAuthParam(array('response_mode' => 'form_post'));
$oidc->authenticate();
}

public function Callback()
{
$token = (new Parser())->parse((string)$_POST['id_token']); // Parses from a string
$user = new User();
$user->name = $token->getClaim('TrueName');
$user->id = $token->getClaim('Id');
//这里可以保存登陆用户
$user = User::where('openid',$token->getClaim('Id'))->first();
if (!$user)
$user = new User();
$user->openid = $token->getClaim('Id');
$user->name = $token->getClaim('TrueName');
$user->photo = $token->getClaim('Photo');
$user->position = $token->getClaim('Position');
$user->save();
Auth::login($user);
return redirect('/');
}
}

添加路由

Route::get('/', 'HomeController@Index');
Route::get('login', 'AuthController@Login')->name('login');
Route::post('callback', 'AuthController@Callback')->name('callback');

还需配置用户表以保存用户

class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password',
];

/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];

/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
protected $dateFormat = 'U';
}

5、php API接口保护

API接口保护,使用中间件,进行接口验证
生成中间件

php artisan make:middleware CheckToken

中间件验证逻辑

$token = (string)$request->id_token;

//本地验证
//$token = (new Parser())->parse((String)$token);
//$signer = new Sha256();
//$publicKey = new Key('file://F:\...\cas.clientservice.cer'); // 公钥证书地址
//if (!$token->verify($signer, $publicKey)) {
// return '验证错误';
//}
//if ($token->getClaim('exp') < time()) {
// return '过期错误';
//}
//if ($token->getClaim('client_id')!='EM') {
// return '客户端ID错误';
//}
//接口验证
$post_data = array(
'client_id' => 'PClientAPI', //是api中的id 不是ids4中的client的id
'client_secret' => '8c31656b4acb74f15bf0d2378d8be3e7',
'token' => $token
);
$postdata = http_build_query($post_data);
$options = array(
'http' => array(
'method' => 'POST',
'header' => 'Content-type:application/x-www-form-urlencoded',
'content' => $postdata,
'timeout' => 15 * 60 // 超时时间(单位:s)
)
);
$context = stream_context_create($options);
$result = file_get_contents('http://localhost:5000/connect/introspect', false, $context);
$request->Cliams = json_decode($result);
if ($result && json_decode($result)->active)
return $next($request);
else
return response()->json(['error' => 'Unauthenticated.'], 401);

分配中间件到指定路由
如果你想要分配中间件到指定路由,首先应该在 app/Http/Kernel.php 文件中分配给该中间件一个 key,默认情况下,该类的 $routeMiddleware 属性包含了 Laravel 自带的中间件,要添加你自己的中间件,只需要将其追加到后面并为其分配一个 key,例如:

protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'token' => CheckToken::class
];

中间件在 HTTP Kernel 中被定义后,可以使用 middleware 方法将其分配到路由:

Route::get('/', function () {
//
})->middleware('token');
获取在控制器中
public function __construct()
{
$this->middleware('token');
}