如何在Laravel Auth中多用户问题,Laravel auth multiple authentication

2019-03-13 07:37:40   Laravel

需要PHP 7 +,Laravel 5.6 +,Composer和Laravel安装程序。有关PHP和Laravel的一些知识。

如果您已经使用了Laravel一段时间,您应该已经听过很多关于多重身份验证的信息。你应该也听过很多guard。但是,如果您对Laravel还不熟悉,则可以通过多种身份验证让不同类别的用户访问同一应用程序的不同/类似部分。 您可能希望在Laravel应用程序中使用多个身份验证的原因有很多。例如,您有一个运行整个公司的大型应用程序。客户还通过相同的应用程序与公司的产品和服务进行交互。该应用程序还有一个博客,公司中有一个部门负责处理博客。 我们可以从上面的应用程序中看到已经有三组用户。对于客户,我们可以让他们使用特定的身份验证过程来访问系统。对于编写者来说,他们可以拥有完全不同的身份验证流程,甚至可以拥有角色来实现更强大的内容管理流程。对于公司的其他人,您可以拥有代表不同功能的不同角色。 现在,让我们看看如何为不同类别的用户创建多个身份验证。


环境

  • PHP知识(版本> = 7.1.3)。
  • 了解Laravel(版本5.6.x)。
  • Composer已安装在您的计算机上(版本> = 1.3.2)。
  • Laravel安装程序已安装在您的计算机上。

入门

  • 如果您检查了先决条件列表中的所有项目,那么本教程已经非常适合您。我们将创建一个Laravel应用程序,它有三个用户类 - 管理员,编写者,用户。我们将为这三个用户类制作guard(警卫),并根据这些guard限制我们应用程序的不同部分。

创建应用程序

我们需要创建一个新的Laravel应用程序。在终端上运行以下命令以创建新的Laravel应用程序:

laravel new multi-auth
cd multi-auth

创建数据库

我们将使用SQLite数据库作为我们的应用程序。它重量轻,速度快,使用简单的文件。使用以下命令创建数据库文件:

touch database/database.sqlite

打开.env应用程序目录中的文件并更改以下部分:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret

改为:

DB_CONNECTION=/absolute/path/to/database.sqlite

这将确保我们的应用程序使用SQLite驱动程序进行数据库连接。

创建迁移

当Laravel附带用户迁移时,我们将为管理员和编写者表进行迁移。它们将像users表一样简单,但您可以根据您的特定需求进一步扩展它们。

为管理员创建迁移

要创建admins表,请运行以下命令:

php artisan make:migration create_admins_table

database/migrations目录中打开admins迁移文件并按如下所示进行编辑:

    // database/migrations/<timestamp>_create_admins_table.php

    [...]
    public function up()
    {
        Schema::create('admins', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->string('password');
            $table->boolean('is_super')->default(false);
            $table->rememberToken();
            $table->timestamps();
        });
    }
    [...]

我们创建了一个简单的迁移,并定义了我们希望管理表具有的列。Eloquent提供了表示数据库表的数据类型的方法。我们使用它们来定义表列的数据类型。

请记住,您可以随时配置您的表。

为作者创建迁移

要创建writers表,请运行以下命令:

php artisan make:migration create_writers_table

现在,打开编写器迁移文件并按如下所示进行编辑:

    database/migrations/<timestamp>_create_writers_table.php
    [...]
    public function up()
    {
        Schema::create('writers', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->string('password');
            $table->boolean('is_editor')->default(false);
            $table->rememberToken();
            $table->timestamps();
        });
    }
    [...]

我们刚刚创建了一个简单的迁移,并定义了我们希望writers表拥有的列。Eloquent提供了表示数据库表的数据类型的方法,因此很容易确定我们想要的每个数据类型。

迁移数据库

现在我们已经定义了表,让我们迁移数据库:

php artisan migrate

设置模型(Model)

我们的应用程序有不同类别的用户,他们使用不同的数据库表。要使用这些不同的表进行身份验证,我们必须为它们定义模型。这些模型将类似于用户模型并扩展Authenticable类。

Admin Model

要为管理员创建模型,请运行以下命令:

php artisan make:model Admin

打开Admin模型app/Admin.php并添加以下内容:

    // app/Admin.php
    <?php

    namespace App;

    use Illuminate\Notifications\Notifiable;
    use Illuminate\Foundation\Auth\User as Authenticatable;

    class Admin extends Authenticatable
    {
        use Notifiable;

        protected $guard = 'admin';

        protected $fillable = [
            'name', 'email', 'password',
        ];

        protected $hidden = [
            'password', 'remember_token',
        ];
    }

当您打算使用模型进行身份验证,并且计划不使用默认user guard时,请务必指定它将使用的guard。在我们的例子中,它将使用admin guard

我们还将一些数据库列定义为可填充的,将它们放在可填充数组中。这告诉Laravel关于模型的以下内容:

当我调用你的create或update方法并且我传给你一个数组时,只取这些项目(读取:fillable数组的字段)。

这样,我们将阻止用户可以绕过我们的任何检查并插入或更新我们不希望他们更新的记录的情况。

对于hidden数组,当我们将模型返回到API或视图时,我们告诉Laravel不要返回这些列。

Writer Model

要为Writer创建模型,请运行以下命令:

php artisan make:model Writer

然后打开Writer模型并替换为以下内容:

    // app/Writer.php
    <?php

    namespace App;

    use Illuminate\Notifications\Notifiable;
    use Illuminate\Foundation\Auth\User as Authenticatable;

    class Writer extends Authenticatable
    {
        use Notifiable;

        protected $guard = 'writer';

        protected $fillable = [
            'name', 'email', 'password',
        ];

        protected $hidden = [
            'password', 'remember_token',
        ];
    }

定义guard

Laravel guard 定义了如何为每个请求对用户进行身份验证。Laravel带有一些用于身份验证的guard,但我们也可以创建我们的。这将使我们能够与我们Admin和Writer模型一样使用Laravel默认的身份验证系统。

打开config/auth.php并添加新的guard编辑如下:

    // config/auth.php

    <?php

    [...]
    'guards' => [
        [...]
        'admin' => [
            'driver' => 'session',
            'provider' => 'admins',
        ],
        'writer' => [
            'driver' => 'session',
            'provider' => 'writers',
        ],
    ],
    [...]

我们增加了两个新guard:adminwriter并设置了他们的providers。当我们尝试使用guard时,这些providers告诉Laravel用于authenticationvalidation的内容。

现在,将以下内容添加到providers数组:

    // config/auth.php

    [...]
    'providers' => [
        [...]
        'admins' => [
            'driver' => 'eloquent',
            'model' => App\Admin::class,
        ],
        'writers' => [
            'driver' => 'eloquent',
            'model' => App\Writer::class,
        ],
    ],
    [...]

现在,我们已经设置了我们定义的provider以及上面的guard。我们设置driver是eloquent因为我们使用Eloquent ORM作为我们的数据库管理器。

假设我们希望使用另一个像database这样的ORM 来管理我们的数据库,然后我们可以设置driverdatabase代替eloquent。对于模型,我们传递我们希望该provider使用的model

设置Controller

要使用我们的guard进行身份验证,我们可以修改现有的身份验证Controller或创建新的身份验证控 您可以根据自己的特定需求选择使用哪种。在本教程中,我们将修改这些Controller。

修改LoginController

打开app/Http/Controllers/Auth中的LoginController,编辑如下:

    // app/Http/Controllers/Auth/LoginController.php

    <?php

    namespace App\Http\Controllers\Auth;

    use App\Http\Controllers\Controller;
    use Illuminate\Foundation\Auth\AuthenticatesUsers;
    [...]
    use Illuminate\Http\Request;
    use Auth;
    [...]
    class LoginController extends Controller
    {
        [...]
        public function __construct()
        {
            $this->middleware('guest')->except('logout');
            $this->middleware('guest:admin')->except('logout');
            $this->middleware('guest:writer')->except('logout');
        }
        [...]
    }

我们设置中间件middleware来限制对此控制器或其方法的访问。重要的是我们在控制器中定义了所有不同类型的客户。这样,如果登录了一种类型的用户,并且您尝试使用其他用户类型登录,则会将您重定向到预定义的身份验证页面。

这样看:如果我以admin身份登录我的计算机,而我作为writer的同事也试图以writer身份登录他的帐户,他将无法这样做。

此检查很重要,因此我们不会弄乱会话信息并可能损坏我们的应用程序数据。

现在,定义管理员的登录信息:

    // app/Http/Controllers/Auth/LoginController.php

    [...]
    public function showAdminLoginForm()
    {
        return view('auth.login', ['url' => 'admin']);
    }

    public function adminLogin(Request $request)
    {
        $this->validate($request, [
            'email'   => 'required|email',
            'password' => 'required|min:6'
        ]);

        if (Auth::guard('admin')->attempt(['email' => $request->email, 'password' => $request->password], $request->get('remember'))) {

            return redirect()->intended('/admin');
        }
        return back()->withInput($request->only('email', 'remember'));
    }
    [...]

我们已经设置了一个方法来返回admin的登录页面。我们将对所有用户类型使用相同的页面,并仅更改它们发送到的URL。为我们节省了许多我们可以避免编写的代码。

我们还定义了adminLogin检查是否提供了正确凭据的方法。然后我们尝试用admin guard 记录用户。在尝试登录时设置此guard非常重要,以便Auth Facade将检查正确的表匹配凭据。它还将设置我们的身份验证,以便我们可以根据登录用户的类型限制页面。

我们将经过身份验证的用户重定向到特定URL,并将未经身份验证的用户发送回登录页面。

现在,让我们为writer做同样的事情:

    // app/Http/Controllers/Auth/LoginController.php

    [...]
    public function showWriterLoginForm()
    {
        return view('auth.login', ['url' => 'writer']);
    }

    public function writerLogin(Request $request)
    {
        $this->validate($request, [
            'email'   => 'required|email',
            'password' => 'required|min:6'
        ]);

        if (Auth::guard('writer')->attempt(['email' => $request->email, 'password' => $request->password], $request->get('remember'))) {

            return redirect()->intended('/writer');
        }
        return back()->withInput($request->only('email', 'remember'));
    }
    [...]

修改RegisterController

打开RegisterController并编辑如下:

    // app/Http/Controllers/Auth/RegisterController.php

    <?php
    [...]
    namespace App\Http\Controllers\Auth;
    use App\User;
    use App\Admin;
    use App\Writer;
    use App\Http\Controllers\Controller;
    use Illuminate\Support\Facades\Hash;
    use Illuminate\Support\Facades\Validator;
    use Illuminate\Foundation\Auth\RegistersUsers;
    use Illuminate\Http\Request;
    [...]
    class RegisterController extends Controller
    {
        [...]
        public function __construct()
        {
            $this->middleware('guest');
            $this->middleware('guest:admin');
            $this->middleware('guest:writer');
        }
      [...]
    }

我们已经设置了控制器将使用的中间件,就像我们使用的那样LoginController

现在,让我们设置方法来返回不同用户的注册页面:

    // app/Http/Controllers/Auth/RegisterController.php

    [...]
    public function showAdminRegisterForm()
    {
        return view('auth.register', ['url' => 'admin']);
    }

    public function showWriterRegisterForm()
    {
        return view('auth.register', ['url' => 'writer']);
    }
    [...]

这与我们为显示不同的登录页面所做的类似。

现在,我们可以定义创建admin的方法:

    // app/Http/Controllers/Auth/RegisterController.php

    [...] 
    protected function createAdmin(Request $request)
    {
        $this->validator($request->all())->validate();
        $admin = Admin::create([
            'name' => $request['name'],
            'email' => $request['email'],
            'password' => Hash::make($request['password']),
        ]);
        return redirect()->intended('login/admin');
    }
    [...] 

接下来,让我们定义创建writer的方法:

    // app/Http/Controllers/Auth/RegisterController.php

    [...] 
    protected function createWriter(Request $request)
    {
        $this->validator($request->all())->validate();
        $writer = Writer::create([
            'name' => $request['name'],
            'email' => $request['email'],
            'password' => Hash::make($request['password']),
        ]);
        return redirect()->intended('login/writer');
    }
    [...] 

还有一点很重要,默认的validator方法指定了emailunique并且表为users,我们可以把这个验证删除,或者我们定义多个验证器,为writer,admin重新定义两个方法。这里我们就先简单的删除这个unique的验证,然后像这样:

protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'email', 'max:255'],    // 原来这一行是`'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],`
            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);
    }

注册完成。

设置身份验证页面

我们将使用Laravel的auth脚手架为我们的身份验证系统生成页面和控制器。运行以下命令以生成身份验证页面:

php artisan make:auth

这将生成视图文件resources/views/auth以及处理我们的应用程序的基本身份验证的路由。

打开login.blade.php文件并进行如下编辑:

    // resources/views/auth/login.blade.php
    [...]
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header"> {{ isset($url) ? ucwords($url) : ""}} {{ __('Login') }}</div>

                    <div class="card-body">
                        @isset($url)
                        <form method="POST" action='{{ url("login/$url") }}' aria-label="{{ __('Login') }}">
                        @else
                        <form method="POST" action="{{ route('login') }}" aria-label="{{ __('Login') }}">
                        @endisset
                            @csrf
        [...]
    </div>

我们正在检查是否url在调用它时将参数传递给页面。如果我们这样做,我们修改表单操作以使用该url参数。我们还修改了表单的标题,以便根据登录参数显示用户类型。

打开register.blade.php文件并进行如下编辑:

    // resources/views/auth/register.blade.php

    [...]
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header"> {{ isset($url) ? ucwords($url) : ""}} {{ __('Register') }}</div>

                    <div class="card-body">
                        @isset($url)
                        <form method="POST" action='{{ url("register/$url") }}' aria-label="{{ __('Register') }}">
                        @else
                        <form method="POST" action="{{ route('register') }}" aria-label="{{ __('Register') }}">
                        @endisset
                            @csrf
        [...]
    </div>

我们在这里复制了我们为登录页面做的事情。

创建经过身份验证的用户将访问的页面

现在我们已经完成了登录和注册页面的设置,让我们创建adminwriter在进行身份验证时会看到的页面。打开终端并运行以下命令以创建新文件。接下来,我们将相应的代码片段插入到文件中。

touch resources/views/layouts/auth.blade.php
touch resources/views/admin.blade.php
touch resources/views/writer.blade.php
touch resources/views/home.blade.php

将此代码块插入auth.blade.php文件中:

    // resources/views/layouts/auth.blade.php

    <!DOCTYPE html>
    <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <!-- CSRF Token -->
        <meta name="csrf-token" content="{{ csrf_token() }}">

        <title>{{ config('app.name', 'Laravel') }}</title>

        <!-- Scripts -->
        <script src="{{ asset('js/app.js') }}" defer></script>

        <!-- Fonts -->
        <link rel="dns-prefetch" href="https://fonts.gstatic.com">
        <link href="https://fonts.googleapis.com/css?family=Raleway:300,400,600" rel="stylesheet" type="text/css">

        <!-- Styles -->
        <link href="{{ asset('css/app.css') }}" rel="stylesheet">
    </head>
    <body>
        <div id="app">
            <nav class="navbar navbar-expand-md navbar-light navbar-laravel">
                <div class="container">
                    <a class="navbar-brand" href="{{ url('/') }}">
                        {{ config('app.name', 'Laravel') }}
                    </a>
                    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
                        <span class="navbar-toggler-icon"></span>
                    </button>

                    <div class="collapse navbar-collapse" id="navbarSupportedContent">
                        <!-- Left Side Of Navbar -->
                        <ul class="navbar-nav mr-auto">

                        </ul>

                        <!-- Right Side Of Navbar -->
                        <ul class="navbar-nav ml-auto">
                            <!-- Authentication Links -->
                           <li class="nav-item dropdown">
                                <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
                                    Hi There <span class="caret"></span>
                                </a>

                                <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
                                    <a class="dropdown-item" href="{{ route('logout') }}"
                                       onclick="event.preventDefault();
                                                     document.getElementById('logout-form').submit();">
                                        {{ __('Logout') }}
                                    </a>

                                    <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
                                        @csrf
                                    </form>
                                </div>
                            </li>
                        </ul>
                    </div>
                </div>
            </nav>

            <main class="py-4">
                @yield('content')
            </main>
        </div>
    </body>
    </html>

接下来,将此代码块插入到admin.blade.php文件中:

    // resources/views/admin.blade.php

    @extends('layouts.auth')

    @section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">Dashboard</div>

                    <div class="card-body">
                        Hi boss!
                    </div>
                </div>
            </div>
        </div>
    </div>
    @endsection

打开writer.blade.php文件并进行如下编辑:

    // resources/views/writer.blade.php

    @extends('layouts.auth')

    @section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">Dashboard</div>

                    <div class="card-body">
                        Hi there, awesome writer
                    </div>
                </div>
            </div>
        </div>
    </div>
    @endsection

最后,打开home.blade.php文件并替换为以下内容:

    // resources/views/home.blade.php

    @extends('layouts.auth')

    @section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">Dashboard</div>

                    <div class="card-body">
                         Hi there, regular user
                    </div>
                </div>
            </div>
        </div>
    </div>
    @endsection

设置Route

我们的应用程序已准备就绪 让我们定义访问到目前为止我们创建的所有页面的路由。打开routes/web.php文件并替换为以下内容:

    // routes/web.php

    <?php
    Route::view('/', 'welcome');
    Auth::routes();

    Route::get('/login/admin', 'Auth\LoginController@showAdminLoginForm');
    Route::get('/login/writer', 'Auth\LoginController@showWriterLoginForm');
    Route::get('/register/admin', 'Auth\RegisterController@showAdminRegisterForm');
    Route::get('/register/writer', 'Auth\RegisterController@showWriterRegisterForm');

    Route::post('/login/admin', 'Auth\LoginController@adminLogin');
    Route::post('/login/writer', 'Auth\LoginController@writerLogin');
    Route::post('/register/admin', 'Auth\RegisterController@createAdmin');
    Route::post('/register/writer', 'Auth\RegisterController@createWriter');

    Route::view('/home', 'home')->middleware('auth');
    Route::view('/admin', 'admin')->middleware('auth:admin');
    Route::view('/writer', 'writer')->middleware('auth:writer');

如果经过身份验证,请修改用户的重定向方式

在身份验证时修改用户的重定向方式非常重要。默认情况下,Laravel会将所有经过身份验证的用户重定向到/home。如果我们不修改重定向,我们将得到以下错误。

redirect error

因此,要解决此问题,请打开app/Http/Controllers/Middleware内的RedirectIfAuthenticated.php文件并替换为:

    // app/Http/Controllers/Middleware/RedirectIfAuthenticated.php

    <?php

    namespace App\Http\Middleware;

    use Closure;
    use Illuminate\Support\Facades\Auth;

    class RedirectIfAuthenticated
    {
        public function handle($request, Closure $next, $guard = null)
        {
            if ($guard == "admin" && Auth::guard($guard)->check()) {
                return redirect('/admin');
            }
            if ($guard == "writer" && Auth::guard($guard)->check()) {
                return redirect('/writer');
            }
            if (Auth::guard($guard)->check()) {
                return redirect('/home');
            }

            return $next($request);
        }
    }

所述RedirectIfAuthenticated中间件接收AUTHguard件作为参数。当我们尝试访问任何针对经过身份验证的用户的页面时,会触发此中间件。然后,我们可以确定用户具有的身份验证类型,并相应地重定向它们。

类似地,要使用auth中间件的话,需要修改app/Http/Controllers/Middleware 中的 Authenticate,php, 添加如下函数

public function handle($request, Closure $next, ...$guards)
    {
        if ($guards[0] == 'admin' && !Auth::guard($guards[0])->check()) {
            return redirect('login/admin');
        }
        if ($guards[0] == 'writer' && !Auth::guard($guards[0])->check()) {
            return redirect('login/writer');
        }
        if (Auth::guard()->check()) {
            return redirect('/home');
        }

        return $next($request);
    }

修改认证异常处理程序

当用户被重定向时会发生一些令人讨厌的事情。你会期望,如果用户试图访问说/writer但未经过身份验证,那么用户被重定向到/login/writer,是吗?好吧,他们没有。他们被重定向到/login 我们想要的不是。

为了确保当用户试图访问/writer它们被重定向到/login/writer或相同时/admin,我们必须修改异常处理程序。打开处理程序文件app/Exceptions并添加以下内容:

    // app/Exceptions/Handler.php

    <?php

    namespace App\Exceptions;

    use Exception;
    use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
    [...]
    use Illuminate\Auth\AuthenticationException;
    use Auth; 
    [...]
    class Handler extends ExceptionHandler
    {
       [...] 
        protected function unauthenticated($request, AuthenticationException $exception)
        {
            if ($request->expectsJson()) {
                return response()->json(['error' => 'Unauthenticated.'], 401);
            }
            if ($request->is('admin') || $request->is('admin/*')) {
                return redirect()->guest('/login/admin');
            }
            if ($request->is('writer') || $request->is('writer/*')) {
                return redirect()->guest('/login/writer');
            }
            return redirect()->guest(route('login'));
        }
    }

unauthenticated我们刚刚添加的方法解决了我们遇到的这个问题。它AuthenticationExpection默认接收一个异常,它携带该guard信息。遗憾的是,我们无法访问它,因为它受到保护(希望Laravel 5.7能够提供访问它的方法)。

我们的解决方法是使用request→is()。这会检查我们尝试访问的URL。如果我们没有绝对URL或者我们有路由组,它也可以检查URL模式。

在我们的例子中,我们首先检查是否收到了JSON请求并单独处理异常。然后我们检查我们是否正在尝试访问/admin或者之前的任何URL admin。我们将用户重定向到相应的登录页面。我们也做检查writer

这对我们来说是一个很好的解决方法,但这意味着我们必须知道我们想要访问的绝对URL,或者至少对我们的guard保护的所有路由都有相同的前缀。

补充

另外,我们在controller或者blade.php模板文件,或者其他地方,获取当前登录用户的时候是使用:

Auth::guard('admin')->user();

而非

Auth::user();

blade.php中使用标签也类似:

@guest('admin')

总之,一定要指定guard

除了login和register,关于logout我们也可以分别指定。

运行该应用程序

现在我们的应用程序已准备好,运行以下命令来启动它:

php artisan serve

它通常应该可用http://localhost:8000

记得分别访问http://localhost:8000/register/writerhttp://localhost:8000/register/admin注册writeradmin。然后分别访问 http://localhost:8000/login/writerhttp://localhost:8000/login/admin登录writeradmin

结论

在本教程中,我们深入研究了Laravel身份验证。我们定义了多个guard来处理多个身份验证和访问控制。我们还为未经身份验证的用户处理经过身份验证的用户和重定向的重定向。

如果您完全遵循本指南,则可以为具有不同用户类(可能是多用户应用程序)的应用程序设置基本身份验证。尽管如此,尝试扩展你所看到的并分享你想出的东西。

vien.tech版权所有,允许转载,但转载请注明出处和原文链接: https://viencoding.com/article/121
欢迎小伙伴们在下方评论区留言 ~ O(∩_∩)O
文章对我有帮助, 点此请博主吃包辣条 ~ O(∩_∩)O

猜你喜欢


评论

There are no comments yet.
未登录

登录后即可发表评论

登录或注册

亲情非友情链接