Laravel API 服务器上的端点“401 未授权”但在本地主机上工作正常
Laravel API Endpoint "401 Unauthorized" on Server But Works Fine On Localhost
背景
我开发了一个使用 Laravel 作为 API 的 React 应用程序。我已经通过 Passport 添加了登录名,并且一直非常成功地使用个人访问客户端方法。我可以添加新用户和令牌,我可以撤销令牌,我可以重置密码...所有 API 调用(登录和注册除外)都由 API 中间件保护并且可以正常工作。如果我在任何这些调用中从 header 中删除 Bearer ${token}
,由于 ->middleware('auth:api') 包装器,它 returns 401 未经身份验证。
问题
一切都完全按预期工作...直到我将所有内容移至我的 Raspberry Pi 服务器。我一移动所有东西,问题就开始了。我可以登录也可以注册,但是一旦我在流程中的任何端点调用上使用新的承载令牌(我从登录或注册调用中收到),它失败并显示 401 未经身份验证,立即 。我 运行 php artisan passport:client --personal
命令并像往常一样成功地将 id 和 secret 输入到我的 .env 文件中。我安装了所有的作曲家和供应商包。我安装了所有护照包和 CLI 命令。
它只会在使用 auth 中间件的调用上失败。
我已经做了一些挖掘,似乎我能找到的唯一变化(显着)是 Pi 运行 32 位 PHP 而我的本地主机运行 64 位 PHP。除了它相同的代码、数据库、Laravel 和 PHP 的版本之外,一切都一样。
我尝试使用命令 php artisan passport:client --personal --name="app-name" --redirect_uri="http://192.168.1.1/"
,它在“oauth_clients”table 中添加一条记录,但显示重定向为 http://localhost/
。然后,我尝试使用 SQL 将名为“redirect”的列的值手动更改为 http://localhost/
,但此更改同样没有任何作用。调用仍然 return 401 未经身份验证。
我能找到的唯一可能有问题的是:
- 数据库 table“oauth_access_tokens”中名为“redirect”的列下的所有标记都是使用
redirect_uri
或 http://localhost
创建的。无论我做什么,它始终是本地主机,而不是我的服务器域或 IP 地址(这是有关的)。像我说的那样手动更改 SQL 什么也没做,但我知道 Laravel 使用一些“read-only”列进行身份验证,所以我想知道这是否是其中之一......也许只是个人访问令牌在本地主机上工作?
- 我的“用户”table 中的
email_verified_at
列(由护照命令生成)为空,因为我无法在本地主机上设置 Passport 的“忘记密码”流程,因为电子邮件不会在本地主机上发送。
我的设置是这样的:
public function boot()
{
$this->registerPolicies();
Passport::pruneRevokedTokens();
Passport::tokensExpireIn(Carbon::now()->addDays(1));
Passport::refreshTokensExpireIn(Carbon::now()->addDays(14));
Passport::personalAccessTokensExpireIn(Carbon::now()->addDays(1));
}
AuthServiceProvider Class
public function register(Request $request) {
$validatedData = $request->validate([
'image_url' => 'required',
'last_name' => 'required|max:55',
'image_url' => 'required|max:250',
'first_name' => 'required|max:55',
'password' => 'required|confirmed',
'email' => 'email|required|unique:users',
]);
$validatedData['password'] = bcrypt($request->password);
if ($request->hasFile('image_url')) {
$imageFile = $request->file('image_url');
$imageExtension = $imageFile->extension();
if (strtolower($imageExtension) === 'png' || strtolower($imageExtension) === 'jpg') {
$validatedData['image_url'] = Storage::url( $request->file('image_url')->store('user_pics', 'public') );
}
$user = User::create($validatedData);
date_default_timezone_set('UTC');
$date = new \DateTime( date('Y-m-d H:i:s') );
$user->email_verified_at = $date->format('c');
$accessToken = $user->createToken('authToken-'.$user->id, ['*'])->accessToken;
return response([ 'user' => $user, 'access_token' => $accessToken ]);
} else {
abort(404, 'Cannot register user without a user image!');
}
}
public function login(Request $request) {
$loginData = $request->validate([
'email' => 'email|required',
'password' => 'required'
]);
if (!auth()->attempt($loginData)) {
return response()->json(['statusText' => 'Unauthorized'], 401);
}
$user = auth()->user();
$accessToken = auth()->user()->createToken('authToken-'.$user->id, ['*'])->accessToken;
return response([ 'user' => $user, 'access_token' => $accessToken ]);
}
public function logout(Request $request) {
if (auth()->guard('api')->check()) {
auth()->guard('api')->user()->OauthAcessToken()->delete();
return response()->json([ 'msg' => 'Successfully logged out!' ]);
} else {
return abort(404, 'Must be logged in to log a user out');
}
}
public function refreshToken(Request $request) {
if (auth()->guard('api')->check()) {
$user = auth()->user();
$accessToken = auth()->user()->createToken('authToken-'.$user->id, ['*'])->accessToken;
return response([ 'user' => $user, 'access_token' => $accessToken ]);
} else {
return abort(404, 'Must be logged in to refresh a token!');
}
}
AuthController Class
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users'
],
],
config/Auth.php
APP_NAME=MyName
APP_ENV=dev
APP_DEBUG=true
APP_URL=http://192.168.1.1
PASSPORT_PERSONAL_ACCESS_CLIENT_ID="1"
PASSPORT_PERSONAL_ACCESS_CLIENT_SECRET="[SOME LONG HASH]"
.env File
终于解决了!!
原来是 Raspberry Pi 服务器上的 Apache 阻止了授权 header。这终于解除了我的封锁并解决了我的问题。
对于来自 Google 搜索的任何其他人,您可以进入 /etc/apache2/apache2.conf
文件并在最底部粘贴:
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=
我正在使用 32 位 PHP 和 Apache2 的 Raspberry Pi 4。
此外,我没有在我的 post 中提到我一直在为我的 apache 服务器根 htaccess 使用以下内容:
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
.htaccess file, server root
背景
我开发了一个使用 Laravel 作为 API 的 React 应用程序。我已经通过 Passport 添加了登录名,并且一直非常成功地使用个人访问客户端方法。我可以添加新用户和令牌,我可以撤销令牌,我可以重置密码...所有 API 调用(登录和注册除外)都由 API 中间件保护并且可以正常工作。如果我在任何这些调用中从 header 中删除 Bearer ${token}
,由于 ->middleware('auth:api') 包装器,它 returns 401 未经身份验证。
问题
一切都完全按预期工作...直到我将所有内容移至我的 Raspberry Pi 服务器。我一移动所有东西,问题就开始了。我可以登录也可以注册,但是一旦我在流程中的任何端点调用上使用新的承载令牌(我从登录或注册调用中收到),它失败并显示 401 未经身份验证,立即 。我 运行 php artisan passport:client --personal
命令并像往常一样成功地将 id 和 secret 输入到我的 .env 文件中。我安装了所有的作曲家和供应商包。我安装了所有护照包和 CLI 命令。
它只会在使用 auth 中间件的调用上失败。
我已经做了一些挖掘,似乎我能找到的唯一变化(显着)是 Pi 运行 32 位 PHP 而我的本地主机运行 64 位 PHP。除了它相同的代码、数据库、Laravel 和 PHP 的版本之外,一切都一样。
我尝试使用命令 php artisan passport:client --personal --name="app-name" --redirect_uri="http://192.168.1.1/"
,它在“oauth_clients”table 中添加一条记录,但显示重定向为 http://localhost/
。然后,我尝试使用 SQL 将名为“redirect”的列的值手动更改为 http://localhost/
,但此更改同样没有任何作用。调用仍然 return 401 未经身份验证。
我能找到的唯一可能有问题的是:
- 数据库 table“oauth_access_tokens”中名为“redirect”的列下的所有标记都是使用
redirect_uri
或http://localhost
创建的。无论我做什么,它始终是本地主机,而不是我的服务器域或 IP 地址(这是有关的)。像我说的那样手动更改 SQL 什么也没做,但我知道 Laravel 使用一些“read-only”列进行身份验证,所以我想知道这是否是其中之一......也许只是个人访问令牌在本地主机上工作? - 我的“用户”table 中的
email_verified_at
列(由护照命令生成)为空,因为我无法在本地主机上设置 Passport 的“忘记密码”流程,因为电子邮件不会在本地主机上发送。
我的设置是这样的:
public function boot()
{
$this->registerPolicies();
Passport::pruneRevokedTokens();
Passport::tokensExpireIn(Carbon::now()->addDays(1));
Passport::refreshTokensExpireIn(Carbon::now()->addDays(14));
Passport::personalAccessTokensExpireIn(Carbon::now()->addDays(1));
}
AuthServiceProvider Class
public function register(Request $request) {
$validatedData = $request->validate([
'image_url' => 'required',
'last_name' => 'required|max:55',
'image_url' => 'required|max:250',
'first_name' => 'required|max:55',
'password' => 'required|confirmed',
'email' => 'email|required|unique:users',
]);
$validatedData['password'] = bcrypt($request->password);
if ($request->hasFile('image_url')) {
$imageFile = $request->file('image_url');
$imageExtension = $imageFile->extension();
if (strtolower($imageExtension) === 'png' || strtolower($imageExtension) === 'jpg') {
$validatedData['image_url'] = Storage::url( $request->file('image_url')->store('user_pics', 'public') );
}
$user = User::create($validatedData);
date_default_timezone_set('UTC');
$date = new \DateTime( date('Y-m-d H:i:s') );
$user->email_verified_at = $date->format('c');
$accessToken = $user->createToken('authToken-'.$user->id, ['*'])->accessToken;
return response([ 'user' => $user, 'access_token' => $accessToken ]);
} else {
abort(404, 'Cannot register user without a user image!');
}
}
public function login(Request $request) {
$loginData = $request->validate([
'email' => 'email|required',
'password' => 'required'
]);
if (!auth()->attempt($loginData)) {
return response()->json(['statusText' => 'Unauthorized'], 401);
}
$user = auth()->user();
$accessToken = auth()->user()->createToken('authToken-'.$user->id, ['*'])->accessToken;
return response([ 'user' => $user, 'access_token' => $accessToken ]);
}
public function logout(Request $request) {
if (auth()->guard('api')->check()) {
auth()->guard('api')->user()->OauthAcessToken()->delete();
return response()->json([ 'msg' => 'Successfully logged out!' ]);
} else {
return abort(404, 'Must be logged in to log a user out');
}
}
public function refreshToken(Request $request) {
if (auth()->guard('api')->check()) {
$user = auth()->user();
$accessToken = auth()->user()->createToken('authToken-'.$user->id, ['*'])->accessToken;
return response([ 'user' => $user, 'access_token' => $accessToken ]);
} else {
return abort(404, 'Must be logged in to refresh a token!');
}
}
AuthController Class
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users'
],
],
config/Auth.php
APP_NAME=MyName
APP_ENV=dev
APP_DEBUG=true
APP_URL=http://192.168.1.1
PASSPORT_PERSONAL_ACCESS_CLIENT_ID="1"
PASSPORT_PERSONAL_ACCESS_CLIENT_SECRET="[SOME LONG HASH]"
.env File
终于解决了!!
原来是 Raspberry Pi 服务器上的 Apache 阻止了授权 header。这终于解除了我的封锁并解决了我的问题。
对于来自 Google 搜索的任何其他人,您可以进入 /etc/apache2/apache2.conf
文件并在最底部粘贴:
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=
我正在使用 32 位 PHP 和 Apache2 的 Raspberry Pi 4。
此外,我没有在我的 post 中提到我一直在为我的 apache 服务器根 htaccess 使用以下内容:
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
.htaccess file, server root