1 原理
1 bilibili 提供一个微信登录的连接,用户点击跳转到微信授权服务器
2 用户根据微信授权服务器提示登录微信并确认授权给bilibili
3 微信授权服务器返回用户代理(浏览器)一个授权码
4 用户代理(浏览器)把这个授权码传给bilibili
5 bilibili凭借授权码向微信授权服务器请求令牌
6 微信授权服务器发送令牌给bilibili
2 授权码模式与密码模式的区别
oauth2支持授权的方式有四种:授权码模式(authorization_code)、密码模式(password)、隐式模式(implicit)、客户端模式(client_credentials)。其中,比较常见的就是授权码模式和密码模式。
2.1 授权码模式的过程
1、封装参数,访问授权服务器登录与授权接口 接口:http://localhost:8080/oauth/authorize 参数:response_type client_id scope redirect_uri state 返回值:code 2、拿到code,获取token 接口:http://localhost:8080/oauth/token 参数:client_id client_secret grant_type code redirect_uri state 返回值:access_token 3、根据token,访问资源 接口:http://localhost:8080/api/test/hello 参数:access_token
2.2 密码模式的过程
1、根据用户名密码等参数直接获取token 接口:http://localhost:8080/oauth/token 参数:username password grant_type client_id client_secret redirect_uri 返回值:access_token 2、根据token,访问资源 接口:http://localhost:8080/api/test/hello 参数:access_token
可以看出,授权码模式和密码模式有些区别,授权码模式多了一步就是登陆。密码模式直接把用户名和密码交给授权服务器了,所以不用再人为登陆,这也要求用户非常信任该应用。
3 创建服务器端 test.weixin.com
3.1 配置
3.1.1 安装项目
composer create-project --prefer-dist laravel/laravel weixin
3.1.2 配置.env 数据库
3.1.3 安装passport组件
cd weixin composer require laravel/passport
3.1.4 Laravel\Passport\HasApiTokens Trait添加到App\User 模型中
\app\Models\User.php
3.2 安装前端
composer require laravel/ui
更新npm版本
linux版本
npm install -g npm@7.12.0
win版本
https://www.jianshu.com/p/caf18c16c2e9
php artisan ui vue --auth
npm install
npn run prod
3.3 准备
3.3.1 安装伪造http请求组件
composer require guzzlehttp/guzzle
3.3.2 auth.php配置
\config\auth.php
'defaults' => [ 'guard' => 'web', 'passwords' => 'users', ],
'api' => [ // 'driver' => 'token', 'driver' => 'passport', 'provider' => 'users', 'hash' => false, ],
3.3.3 数据包安装
php artisan migrate
php artisan passport:keys
3.3.4 注册服务
\app\Providers\AuthServiceProvider.php
use Laravel\Passport\Passport;
public function boot() { $this->registerPolicies(); Passport::routes(); }
3.3.5 注册一个帐号
3.3.6 创建客户端
php artisan passport:client
SELECT * FROM `weixin`.`oauth_clients` WHERE user_id = 1
4 创建客户端 test.bili.com
4.1 准备
4.1.1
composer create-project --prefer-dist laravel/laravel my_bilibili
4.1.2 伪造http请求
composer require guzzlehttp/guzzle
4.2 代码部署
百度盘地址
链接:https://pan.baidu.com/s/1yHXdVu7C7CQzR2ssj9QAXg
提取码:juge
4.2.1 \routes\web.php
//登录页面 Route::view('/login','login'); $clientId = '2'; $clientSecret= 'yeydzuW6lQJqoV8Py5exDK4rK4wcryhi3CrYqrGc'; //第三方登录 重定向 Route::get('/weixin/login', function (\Illuminate\Http\Request $request) use ($clientId) { $request->session()->put('state',$state=\Illuminate\Support\Str::random(40)); $query = http_build_query([ 'client_id' => $clientId, 'redirect_uri' => env('APP_URL').'/auth/callback', 'response_type' => 'code', 'scope' => '*', 'state' => $state, ]); return redirect('http://test.weixin.com/oauth/authorize?'.$query); }); //回调地址 获取code 并随后发出获取token请求 Route::view('/auth/callback','auth_callback'); Route::post('/get/token',function (\Illuminate\Http\Request $request) use( $clientId, $clientSecret ){ //csrf 攻击处理 $state = $request->session()->pull('state'); throw_unless( strlen($state)>0 && $state === $request->params['state'], InvaliaArgumentException::class ); $form_params = [ 'grant_type'=>'authorization_code', 'client_id'=>$clientId, 'client_secret'=>$clientSecret, 'redirect_uri'=>env('APP_URL').'/auth/callback', 'code'=>$request->params['code'], ]; $post = ['form_params'=>$form_params]; $response = (new \GuzzleHttp\Client())->post('http://test.weixin.com/oauth/token',$post); return json_decode((string)$response->getBody(),true); }); //刷新token Route::view('/refresh/page','refresh_page'); Route::post('/refresh',function(\Illuminate\Http\Request $request) use ( $clientId , $clientSecret ){ $http = new GuzzleHttp\Client; $url = 'http://test.weixin.com/oauth/token'; $post = ['form_params'=>[ 'grant_type' => 'refresh_token', 'refresh_token' => $request->params['refresh_token'], 'client_id' => $clientId, 'client_secret' => $clientSecret ]]; $response = $http->post($url,$post); return json_decode((string)$response->getBody(),true); });
4.2.2 登录页面 \resources\views\login.blade.php
<a href="/weixin/login"> 微信登录 </a>
4.2.3 回调页 \resources\views\auth_callback.blade.php
<script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script> function GetRequest() { var url = location.search; //获取url中"?"符后的字串 var theRequest = {}; if (url.indexOf("?") !== -1) { var str = url.substr(1); strs = str.split("&"); for (var i = 0; i < strs.length; i++) { theRequest[strs[i].split("=")[0]] = decodeURI(strs[i].split("=")[1]); } } return theRequest; } //调用 var Request = GetRequest(); if (Request['error']) { // 用户未授权处理 alert(Request['error']); }else { var code = Request['code']; var state = Request['state']; axios.post('/get/token', { params: { code, state } }) .then(function (response) { console.log(response.data); }); } </script>
4.2.4 刷新token页面 \resources\views\refresh_page.blade.php
refresh_token 里填入刚才生成的refresh_token
<script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script> axios.post('/refresh', { params: { refresh_token: "def50200b1a5c2dff9cc299a046e4151134e94174ee05843bc865aee42f2b6209726b45eebc2a9f1faf91ded3c15c9eecf059f48e6a56f70de9226ebba0e922c18b45f478a46c09612bedce26ad48c587a2e5c5c9d8cb4416d02f4746f6d710f70bd782eaf6ebed659510cb2088f7e72900990dc4871a717e96a9c549549a7e0ca5f1dae695e7ad5f8813d711b27f7cf2f0411d881dc29b889cbec283637a2c50ea761af92fef6374264699d0ec10432c27b8edec7a4754ee6f7550b16af9fdba29e591dd96073a28990a18d8404bf9e0c1a63f491e685ea46959e020228276160fd553078e0384eb036ce90fc1fd6db9da1cf4b2d86cff6c1ac0f2bf9a327bf5a9c03e78b1df518937ff811e9399460bb3aa215addca7ed0068b143f6b5d9e9f2e1498d241b0f71717262a91fde12ccb632d04e3be8d82df146f89ed69326cbee237f48fc295a1ca054ef05bcd9ce0cd8d75e3b9f32b68b543840f6f3cf9775c2" } }) .then(function (response) { console.log(response.data); }); </script>
5 测试
5.1 登录
http://test.bili.com/login
生成:
Object {
token_type: "Bearer",
expires_in: 31536000,
access_token: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIyIiwianRpIjoiMjllOTU5ODhjMmE5ZTA4ZWJjODY1MmE0ZGJlMzMxMjgyZWU0NDVhMTgwYjExNjdlZjQzMjA0NGFmMGYwMDA4MDg0NjU1OTJmMTFjNzY3Y2QiLCJpYXQiOjE2MjA4NDIzMzcsIm5iZiI6MTYyMDg0MjMzNywiZXhwIjoxNjUyMzc4MzM3LCJzdWIiOiIyIiwic2NvcGVzIjpbXX0.M6nh-FQ3xHKw1P6PYFhN-ERRksS5ARqANcmseoKFbv4pB_T8YNN33SPRoaOhVaEotN2JzVhzWFd-Q0aizFwDBbhdZHGiw-FeYA_J7jx9Xg8JAkksVegsI9tL1zEenrvHsPY5SktPwI3gUc5Zlwo5bJy_gexzytJ6mkUo1MMEkbCAXGUjNBfxsbIARTbYdCLQsdVudrEcgPomsMtzhB59CtxQJ0A4p9ydvxlawNnY5JJxm98rHUXAkaRIKVYBKDj6MxNJH6pF0E0laowm4j6h7u8pcploZNW5dzwzLM96tth4VrEEtHzaymEREC3sS58IIyaIT1NRSExpjPwa6Zo2algsGTay-yLCcfjCfeWXA0qE-T-8GqB0uvxf257KBHPYIMbUyJR8w1Yg5GcgCZZpXA6gr8JaDdAJJELjeuDkeR4THk4A9GtbLujJVNJHTOXmiQdiMcBgKChvTvQYJOjnp5jMoaSTCa8tOpIHeUBReJjJLkm83PcwULNuLxkI2TSdyawy2Bfgi03mEEc8szCBkKBLmdO41j3LUNuvuUprHC04E16bb1etJsHSy3GscTgebSVkZllKWT-WMEhyDhk_qUpj2J-OrnWuv2FRPd2kzpKN4KS6hSdWSW5samZ9HYQV0ia2rTXL2ya7h7C-cNfeRQ3Z0UZTSUtvaZ_oTiQ9Qt0",
refresh_token: "def502001b3d0ad3fc789f4099ed64edbda21072a40b8d7e78b5f34ecc9f55eb4e22dd0fe75edc46df0be3c3a63c9e3cea27b3f6ccbcab008df466c9288b78330923f2fd0b8dfef58889a4291f6d3d54f9c1a4d8593f7aba57dbf85cdfd7fd9b0df1ea0ea2323d155f318a6d300c6e8b43192364cf9aef9b3aca2eb6d41e40d0613298c148a3a6bc643b0fffe9f9a984d7820fbd8e701b90324be60ddd33e09a8f878c00bfb9a55624ecd11d58d7f8ffd4e871652fa723d80118b95a4618699f10406d9e36982b574d1d013d9ec1300c599c7b74e4f874b174fc3ac7ceaa3b31aa18da562d5d3eb135fa381db0940207b1467c0cdafcd7985f16e3e82695a02f9f99aa78f9e2fc5f55e65a4059781da3baaa105258d9d9a0950aa7ae0b7d8d7a551af170e205df882ca01ab4b7fdbcd1b0b7d59852e0e01bbf2283785a59315823b35c742925305fe5844608c909389e5add80e96485e3270a2349af5564072b21" }
callback:31:25
5.2 刷新
http://test.bili.com/refresh/page
返回:
Object {
token_type: "Bearer",
expires_in: 31536000,
access_token: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIyIiwianRpIjoiMDJiZGFhOWIxMjI3ZGYyMTI0YTcyNjZjZTViNTNlY2Q2ZTUxMDg0OWM2MmJjNzg4NWZkM2I1YjgzM2QwZjEwZjkyMjJhMzUzMTg2MDRjMDkiLCJpYXQiOjE2MjA4NDQzNTAsIm5iZiI6MTYyMDg0NDM1MCwiZXhwIjoxNjUyMzgwMzUwLCJzdWIiOiIyIiwic2NvcGVzIjpbXX0.XqjyoeUYwUmqYZCBkH9SPFEeGUzSCYhaDBjyaoIj3Eanh462SkuG0f1ryNX1W5oaVyGIEvpn8NsDmTD4zi4prGq5U7ipFOTauGXPH7vMTgOTC5s1iVZuKLyxSHIbzCvCAfznbt5_5o1LfWrM3fKvZhQkF0DHNuL58MWGoQI79TTb8yr3wj9KuOTAFtZ4lHEiIBKlcwiOl9PcbeBFsl9CwzAmEEW05w1NqJkABu8Qmx-LQgiUEuFSmB_NAMMcmHRDiWoT4MvM1OClybq0GSngkSFwkWc1r0BpT1vS38BYKTABkljB7aS_GuFc8HPYpk0AKflPkqKvkdIqA1q9uX5dSfDKwi--OTKHz___1Wmy5pXHAUlqvWWnyL-Q7MTqfMA39imeQ9oANxWOm1_jvvj3-0R-KqEMSTPPp8VsNl6YQV4ZoLtlGxzDhlLYbk_MOSLUq4k4xXVjef9M7kOnsF1Uompkd3tshfaI32p0Ws1deMJ_Jr0xnSV4EkE3kjQ_6DMjmDgQks9La2AqI3CFVpILNcvh1NEMz3bs4NtHnmyjdo1beokNkgxaJyTgySEfYtf-NQyMaPSkDIprjqT_IVLmB3OP1QwBvFJzLI_6JrPjMaxI7QGUbgxJQWxoXxJoqmC25X9MDDRRHuL5z_LkYyCFmqFF8xJbATScT6QJV9UF0Zo",
refresh_token: "def50200d100a35326e7d524d65c08cbda19255d61082ead0494b20a7f70fceebfcafef2d0c3fd070da0bf4d2ec76011bf87ed38a8f201eb69c896d21ae500f974b94befb124a4c7c1a6e8d05d0e2885f845257ff5a8d89d1da7620e033771f869e3a43f27cebceacc8c15985e3b134a30b799b4e915f762df3c1c845ff021954c6bc601cac9c5d85f80437016c4aaf6bb642da0396301c0b6ab6560ccd06da302b55821cb2e202d27e12f954559d0bb55a12697dd972f802c0c533cd6a6218e264b369fdd5f1c3f80a1fafe9ad66efaf44802c4ada47f23dba0010f3bdb010249f3991a52a17369cf56e1f10b81c3972c1696d0b47257aeb2e62aa7d18019030b6d2e202b7fbc72772d6ab4889b30931a2fa775c80d2fded545ef4657a661bc9b640f5441129dbcc3ca66b1f25fe57cb49ceda29035a75173860c53a90d3e3d5b380892158449a9b1a06aa21ed582851014e411519fcc995ea34c40c1dd970421" }
6 参考资料
github地址 https://github.com/John0079/bili
passport手册 https://learnku.com/docs/laravel/8.x/passport/9420
7 其他认证
1 Laravel 7 用户认证 Auth ——传统web认证
2 Laravel 7 用户认证 Auth ——内置的API认证
3 Laravel 7 用户认证 Auth ——Passport密码模式认证