基于 Laravel + Vue 构建 API 驱动的前后端分离应用系列(二) —— 安装配置 Laravel Socialite 并实现基于 Github 的用户认证

上一篇教程中,我们完成了 Roast 应用的初始化工作,这一篇教程将在其基础上安装 Laravel Socialite 扩展包并实现基于 Github 进行登录认证,Laravel Socialite 还支持世界上其他主流的社交媒体,你可以在这里找到所有第三方 OAuth 提供者:Socialite Providers,你可以按照自己的需求对第三方 OAuth 服务进行更改,我们这里只是以 Github 为例进行演示,实际上,我们下面编写的代码还支持同时基于多个 OAuth 服务进行登录认证。

安装 Laravel Socialite

Laravel Socialite 文档里,有详细的安装配置说明,这里只是简单几笔带过。

在应用根目录下通过 Composer 安装 Socialite 扩展包:

composer require laravel/socialite

在 Laravel 5.6 中该扩展包会自动发现,所以无需对服务提供者进行注册。

配置 Github 认证

首先登录到 Github 并访问这个页面:https://github.com/settings/developers,点击「New OAuth App」注册一个新 OAuth App:

在github新增oauth app

在github新增oauth app

注册成功之后,即可在跳转后页面看到 Client ID 及 Client Secret 信息:

github roast oauth app

将新增应用的 Client ID、Client Secret 及授权回调 URL 信息添加到应用根目录下 .env 配置文件中:

GIT_CLIENT_ID=你的 Github 应用 Client ID
GIT_CLIENT_SECRET=你的 Github 应用 Client Secret
GIT_REDIRECT=你的 Github 应用授权回调URL

然后在 config/services.php 配置文件中新增如下配置:

'github' => [
    'client_id' => env('GIT_CLIENT_ID'),
    'client_secret' => env('GIT_CLIENT_SECRET'),
    'redirect' => env('GIT_REDIRECT')
]

至此,就完成了基于 Github 登录所需的所有配置信息配置工作,其它第三方 OAuth 登录操作步骤也是与此类似,这里就不再赘述了,感兴趣的同学当做课下作业去完成。

实现基于 Github 进行登录认证

完成配置工作后,接下来我们来编写基于 Github 的认证逻辑实现代码,我们需要为其编写路由、控制器和视图,以及数据库迁移。

首先创建一个控制器 /app/Http/Controllers/Web/AuthenticationController.php

<?php

namespace App\Http\Controllers\Web;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class AuthenticationController extends Controller
{
    //
}

具体实现先留空,先在 routes/web.php 中注册登录路由:

Route::get('/login', 'Web\AppController@getLogin' )
    ->name('login')
    ->middleware('guest');

注意我们在 login 路由上使用了 guest 中间件,该中间件的用途是登录用户访问该路由会跳转到指定认证后页面,而非登录用户访问才会显示登录页面。

需要注意的是,由于我们没有注册 /home 路由, 所以需要修改 app\Http\Middleware\RedirectIfAuthenticated.php 中的跳转路由,将 redirect('/home') 修改为 redirect('/')

接下来在 Web\AppController.php 控制器中定义 getLogin() 方法:

public function getLogin()
{
    return view('login');
}

这样,我们访问 http://roast.test,就会跳转到登录页面了。现在页面上只显示了一个简陋的登录链接,我们现在暂时不关注页面样式问题,这些将留到后面前端部门去优化。

光有登录页面还不够,还要实现真正的登录功能,为此,我们先在 routes/web.php 中注册登录认证路由:

Route::get( '/auth/{social}', 'Web\AuthenticationController@getSocialRedirect' )
      ->middleware('guest');

Route::get( '/auth/{social}/callback', 'Web\AuthenticationController@getSocialCallback' )
      ->middleware('guest');

其中,{social} 参数代表所使用的 OAuth 提供方,比如我们这里使用的是 github,Socialite 会根据这个参数值去 config/services.php 中获取对应的 OAuth 配置信息。

接下来就可以来正式编写基于 Github 的登录认证代码了,首先编写重定向到第三方 OAuth 服务授权页面获取授权码的代码,在 Web/AuthenticationController.php 中新增 getSocialRedirect 方法:

public function getSocialRedirect($account)
{
    try {
        return Socialite::with($account)->redirect();
    } catch (\InvalidArgumentException $e) {
        return redirect('/login');
    }
}

其中 $account 就是路由中传进来的 {social} 参数。如果重定向出现异常就会返回登录页面。

在我们编写授权成功重定向到应用回调 URL 之前,还需要创建数据表保存用户信息,为此,我们需要修改并运行数据库迁移文件,这些数据库迁移文件位于 databases/migration 目录下,在 CreateUsersTable 类的 up() 方法中新增以下三个字段:

$table->string('provider');
$table->string('provider_id');
$table->text('avatar');

provider 字段用于存放 OAuth 服务提供方,在这里就是 github 了, provider_id 用于存放从第三方 OAuth 那里获取的用户唯一ID,而 avatar 字段用于存放从第三方 OAuth 获取的用户头像。

然后删除 CreatePasswordResetsTable 类,在本应用中用不到它。

至此,数据库迁移文件已经准备完毕,在项目根目录下运行以下 Artisan 命令来生成数据表(在此之前,确保已修改 .env 文件中的数据库连接配置):

php artisan migrate

运行成功后就可以在数据库中看到 users 表已经成功创建了:

roast users table

最后,我们在 Web/AuthenticationController.php 中新增 getSocialCallback 方法,该方法用于从第三方 OAuth 回调(这里是 Github)中获取用户信息,如果该用户在 Roast 中不存在的话将其保存到 users 表,然后手动对该用户进行登录认证操作,如果已存在的话直接进行登录操作:

public function getSocialCallback($account)
{
    // 从第三方 OAuth 回调中获取用户信息
    $socialUser = Socialite::with($account)->user();
    // 在本地 users 表中查询该用户来判断是否已存在
    $user = User::where( 'provider_id', '=', $socialUser->id )
        ->where( 'provider', '=', $account )
        ->first();
    if ($user == null) {
        // 如果该用户不存在则将其保存到 users 表
        $newUser = new User();

        $newUser->name        = $socialUser->getName();
        $newUser->email       = $socialUser->getEmail() == '' ? '' : $socialUser->getEmail();
        $newUser->avatar      = $socialUser->getAvatar();
        $newUser->password    = '';
        $newUser->provider    = $account;
        $newUser->provider_id = $socialUser->getId();

        $newUser->save();
        $user = $newUser;
    }

    // 手动登录该用户
    Auth::login( $user );

    // 登录成功后将用户重定向到首页
    return redirect('/');
}

至此,我们已经完成了基于 Socialite 提供的第三方 OAuth 服务实现用户登录认证的所有安装配置和逻辑代码编写,接下来我们就可以访问 http://roast.test/login,点击页面上的登录链接,进行登录了:

授权使用github登录到roast

点击上图中的绿色按钮,表示允许通过 Github 实现 Roast 登录认证,第一次登录会在 users 表中新增一条记录:

登录成功后,页面会跳转到 Roast 应用首页。这还是通过 Web 路由实现的认证,下一篇教程我们将基于 Laravel Passport 实现 API 路由的登录认证操作。

项目源码位于 Github 上:nonfu/roastapp

学院君 has written 1343 articles

Laravel学院院长,终身学习者

积分:187072 等级:P12 职业:手艺人 城市:杭州

81 条回复

  1. 学院君 学院君 says:
    @ com

    你理解错了,这个 clientid 和 secret 是应用级的 id 和 secret ,与用户无关,Laravel 学院的 github 登录就是基于 socialite 的

  2. com com says:
    @ 学院君

    @ 学院君 学院君,你好。 我想问下Laravel Socialite使用github帐号进行第三方登录,是不是只能用限定的一个github帐号(就是生成'client_id' 和 'client_secret'的github帐号)登录? 如果只是想提供一个第三方登录接口,让任何有github帐号的用户都可以实现第三方登录,Laravel Socialite能办到吗?

  3. Gebriel Gebriel says:

    login.blade.php 页面

             <div>
                <h1>跳转链接</h1>
                <a href="{{route('auth','github')}}">跳转跳转跳转点我点我</a>
            </div>

    web.php

    Route::get('/auth/{social}', 'Web\AuthenticationController@getSocialRedirect')->name('auth')
        ->middleware('guest');

    差不多就这样子,刚刚开始郁闷,这个跳转地址i怎么写呢?后面看了文档,才知道。

  4. LJP88 LJP88 says:
    @ LJP88

    解决了,我直接拷github示例代码里Models的User,然后composer require laravel/passport,在config/app.php的providers数组中注册Laravel\Passport\PassportServiceProvider::class,,最后php artisan migrate搞定,现在数据库就有记录了??

  5. LJP88 LJP88 says:
    @ 学院君

    之前是直接use User;才提示那个错误的,现在创建了Models User,命名空间改为use App\Models\User;后登录提示:Symfony \ Component \ Debug \ Exception \ FatalThrowableError (E_RECOVERABLE_ERROR) Argument 1 passed to Illuminate\Auth\SessionGuard::login() must be an instance of Illuminate\Contracts\Auth\Authenticatable, instance of App\Models\User given, called in G:\phpStudy\PHPTutorial\WWW\roast\vendor\laravel\framework\src\Illuminate\Auth\AuthManager.php on line 294

  6. LJP88 LJP88 says:

    按照评论方法下载配置好证书路径后,点击登录提示:Symfony \ Component \ Debug \ Exception \ FatalThrowableError (E_ERROR) Class 'User' not found 再刷新就提示:Laravel \ Socialite \ Two \ InvalidStateException No message User我已经在头部use了的,怎么还提示 'User' not found 呢?

登录后才能进行评论,立即登录?