单点登录 - API 认证系统 Passport(二)
安装
composer require laravel/passport=~4.0
notes:
1)确保系统安装unzip、zip等命令。
2)composer 安装出现 authentication required (packagist.phpcomposer.com) 问题,修改composer.json 中的源,repositories.packagist.url = https://packagist.laravel-china.org 。
注册服务提供者
在config/app.php的providers 数组中加入 laravel\passport\passportserviceprovider::class
迁移数据库
php artisan migrate //生成用于存储客户端和令牌的数据表
生成加密健
php artisan passport:install
1、生成oauth-private.key(用于构建认证服务器),oauth-public.key(用于构建资源服务器)
2、oauth_clients数据库生成「个人访问」客户端和「密码授权]两条数据。
配置passport(参考官方文档)
在model中,我们需要增加 hasapitokens class
在authserviceprovider中, 增加 "passport::routes()"
在 auth.php中, 更改 api 认证方式为passport
申请客户端以及私人访问令牌 (两种方式)
1. 命令形式(不方便客户注册)
php artisan passport:client
2. passport vue 组件
php artisan vendor:publish --tag=passport-components //发布 passport vue,组件位于resources/assets/js/components下
//注册到resources/assets/js/app.js 文件,记得要放在new vue上面
vue.component( 'passport-clients', require('./components/passport/clients.vue') ); vue.component( 'passport-authorized-clients', require('./components/passport/authorizedclients.vue') ); vue.component( 'passport-personal-access-tokens', require('./components/passport/personalaccesstokens.vue') );
//编译前端资源
npm install //此处报错,移步larravel mix文档 npm run dev
编译后资源放在public/js/app.js下
//组件放入应用模板(记得引入编译后的app.js)
<passport-clients></passport-clients> <passport-authorized-clients></passport-authorized-clients> <passport-personal-access-tokens></passport-personal-access-tokens>
以上认证服务器都已经搭建完成
第三方应用实现登录
1. 申请客户端
回调地址 http://third.plat.goods/dew/sso
申请授权码和访问令牌
//获取授权码 code (第一次交互)
$query = http_build_query(array( 'client_id' => 3, 'redirect_uri' => 'http://third.plat.goods/dew/sso', //地址必须为上面的回调地址 'response_type' => 'code', //固定值 'scope' => '', 'state' => urlencode('http://laravel.plat.goods/user') //可以放用户访问的地址。 )); return redirect('http://laravel.plat.goods/oauth/authorize?'.$query); ///laravel.plat.goods为上面认证服务器
//获取访问令牌 access token 以及向资源服务器请求用户信息
授权后会重定向回调地址
route::get('/dew/sso', 'ssocontroller@callback'); //路由文件里添加 php artisan make:controller ssocontroller //创建文件
<?php namespace app\http\controllers; use app\models\user; use guzzlehttp\client; use illuminate\http\request; use illuminate\support\facades\log; class ssocontroller extends controller { protected $http; public function __construct() { $this->http = new client(); } /** * 获取授权码后的回调url * @param request $request * @return \illuminate\http\redirectresponse */ public function callback(request $request) { $token = $this->token($request); //第二次交互 $login = $this->login($token);//第三次交互 if($login){ if($request_url = $request->input('state', null)){ $request->session()->put('url.intended', urldecode($request_url)); } return redirect()->intended(); //跳转到 http://laravel.plat.goods/user }else{ return redirect()->to('http://laravel.plat.com/home/public/login'); //服务提供商网站必须登录 } } /** * 获取access token * @param $request * @return array|mixed */ protected function token($request) { $code = $request->code; if($code) { try { $response = $this->http->post('http://laravel.plat.goods/oauth/token', [ 'form_params' => [ 'grant_type' => 'authorization_code', //固定值 'client_id' => 3, 'client_secret' => 'uihxnhosqohdtq8js6av7aoyk3gbnb9rjzidpawf', 'redirect_uri' => 'http://third.plat.goods/dew/sso', 'code' => $code, ], ]); $response_data = json_decode((string)$response->getbody(), true); return $response_data; } catch (\exception $e) { log::error('get token by code failed: '.$code.' - '.$e->getmessage().' - '.$e->gettraceasstring()); return []; } }else{ return []; } } /** * 通过token获取用户信息,并进行登录操作 * @param $token * @return bool */ protected function login($token) { if(empty($token)) return false; $access_token = $token['access_token']; try { // 资源服务器和认证服务器放在了一起,可以独立。 $response = $this->http->request('get', 'http://laravel.plat.goods/api/user', [ 'headers' => [ 'accept' => 'application/json', 'authorization' => $token['token_type'] . ' ' . $access_token, ] ]); $users_body = $response->getbody(); $data = json_decode($users_body, true); if($data) { $user = new user($data); //because of employee_id is guarded $user->setattribute($user->getkeyname(), $data['employee_id']); //login user in my system auth()->login($user, false); return true; }else{ return false; } }catch (\exception $e){ log::error('get user failed by access_token:'.$access_token.'|'.$e->getmessage()); return false; } } }
//设置资源文件
route::middleware('auth:api')->get('/user', 'usercontroller@user'); //routes/api.php文件中设置 php artisan make:controller usercontroller //创建文件
class usercontroller extends controller { public function user(request $request) { return $request->user(); } }
上一篇: 2019年腾讯PHP程序员面试题目分享
下一篇: 樱桃西红柿和普通西红柿有什么区别呢