Explorar el Código

基于微服务接口重构客户端密码重置功能

chenlong hace 4 años
padre
commit
1b6a4281a2

+ 18 - 0
app/Http/Controllers/Auth/ResetPasswordController.php

@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Auth;
 
 use App\Http\Controllers\Controller;
 use Illuminate\Foundation\Auth\ResetsPasswords;
+use Illuminate\Support\Str;
 
 class ResetPasswordController extends Controller
 {
@@ -35,4 +36,21 @@ class ResetPasswordController extends Controller
     {
         $this->middleware('guest');
     }
+
+    /**
+     * Reset the given user's password.
+     *
+     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
+     * @param  string  $password
+     * @return void
+     */
+    protected function resetPassword($user, $password)
+    {
+        $mciroUserService = resolve('microUserService');
+        $user->password = $password;
+        $user->remember_token = Str::random(60);
+        $mciroUserService->update($user);
+
+        return redirect('/login');
+    }
 }

+ 0 - 0
app/MicroApi/RpcException.php → app/MicroApi/Exceptions/RpcException.php


+ 9 - 0
app/MicroApi/Items/PasswordResetItem.php

@@ -0,0 +1,9 @@
+<?php
+namespace App\MicroApi\Items;
+
+class PasswordResetItem
+{
+    public $email;
+    public $token;
+    public $created_at;
+}

+ 12 - 5
app/MicroApi/Items/UserItem.php

@@ -4,8 +4,15 @@ namespace App\MicroApi\Items;
 
 use Illuminate\Contracts\Auth\Authenticatable;
 
-class UserItem implements Authenticatable
+use Illuminate\Auth\Passwords\CanResetPassword;
+use Illuminate\Notifications\RoutesNotifications;
+use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
+
+class UserItem implements Authenticatable, CanResetPasswordContract
 {
+    use RoutesNotifications, CanResetPassword;
+
+    public $remember_token;
     public $id;
     public $name;
     public $email;
@@ -73,7 +80,7 @@ class UserItem implements Authenticatable
      */
     public function getAuthPassword()
     {
-        // TODO: Implement getAuthPassword() method.
+        return $this->password;
     }
 
     /**
@@ -83,7 +90,7 @@ class UserItem implements Authenticatable
      */
     public function getRememberToken()
     {
-        // TODO: Implement getRememberToken() method.
+        return $this->remember_token;
     }
 
     /**
@@ -94,7 +101,7 @@ class UserItem implements Authenticatable
      */
     public function setRememberToken($value)
     {
-        // TODO: Implement setRememberToken() method.
+        $this->remember_token = $value;
     }
 
     /**
@@ -104,6 +111,6 @@ class UserItem implements Authenticatable
      */
     public function getRememberTokenName()
     {
-        // TODO: Implement getRememberTokenName() method.
+        return 'remember_token';
     }
 }

+ 95 - 0
app/MicroApi/Services/UserService.php

@@ -6,6 +6,7 @@ use App\MicroApi\Facades\HttpClient;
 use App\MicroApi\Items\TokenItem;
 use App\MicroApi\Items\UserItem;
 use Illuminate\Support\Facades\Log;
+use App\MicroApi\Items\PasswordResetItem;
 
 class UserService
 {
@@ -123,4 +124,98 @@ class UserService
         $result = $this->decode($response->getBody()->getContents());
         return isset($result->user) ? $result->user : null;
     }
+
+    /**
+     * 创建密码重置记录
+     *
+     * @param $data
+     * @return PasswordResetItem|null
+     * @throws RpcException
+     */
+    public function createPasswordReset($data)
+    {
+        $path = $this->servicePrefix . '/createPasswordReset';
+        $item = new PasswordResetItem();
+        if (!empty($data['email'])) {
+            $item->email = $data['email'];
+        }
+        if (!empty($data['token'])) {
+            $item->token = $data['token'];
+        }
+        $options = ['json' => $item];
+        try {
+            $response = HttpClient::post($path, $options);
+        } catch (\Exception $exception) {
+            Log::error("MicroApi.UserService.createPasswordReset Call Failed: " . $exception->getMessage());
+            throw new RpcException("调用远程服务失败");
+        }
+        $result = $this->decode($response->getBody()->getContents());
+        return !empty($result->passwordReset) ? $result->passwordReset : null;
+    }
+
+    /**
+     * 删除密码重置记录
+     *
+     * @param $email
+     * @return bool
+     * @throws RpcException
+     */
+    public function deletePasswordReset($email)
+    {
+        $path = $this->servicePrefix . '/deletePasswordReset';
+        $item = new PasswordResetItem();
+        $item->email = $email;
+        $options = ['json' => $item];
+        try {
+            HttpClient::post($path, $options);
+        } catch (\Exception $exception) {
+            Log::error("MicroApi.UserService.deletePasswordReset Call Failed: " . $exception->getMessage());
+            throw new RpcException("调用远程服务失败");
+        }
+        return true;
+    }
+
+    /**
+     * 验证密码重置令牌
+     *
+     * @param $token
+     * @return bool
+     * @throws RpcException
+     */
+    public function validatePasswordResetToken($token)
+    {
+        $path = $this->servicePrefix . '/validatePasswordResetToken';
+        $item = new TokenItem();
+        $item->token = $token;
+        $options = ['json' => $item];
+        try {
+            $response = HttpClient::post($path, $options);
+        } catch (\Exception $exception) {
+            Log::error("MicroApi.UserService.validatePasswordResetToken Call Failed: " . $exception->getMessage());
+            throw new RpcException("调用远程服务失败");
+        }
+        $result = $this->decode($response->getBody()->getContents());
+        return $result->valid;
+    }
+
+    /**
+     * 更新用户信息接口
+     *
+     * @param UserItem $item
+     * @return UserItem
+     * @throws RpcException
+     */
+    public function update(UserItem $item)
+    {
+        $path = $this->servicePrefix . '/update';
+        $options = ['json' => $item];
+        try {
+            $response = HttpClient::post($path, $options);
+        } catch (\Exception $exception) {
+            Log::error("MicroApi.UserService.update Call Failed: " . $exception->getMessage());
+            throw new RpcException("调用远程服务失败");
+        }
+        $result = $this->decode($response->getBody()->getContents());
+        return $result->user;
+    }
 }

+ 25 - 0
app/Providers/PasswordResetServiceProvider.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace App\Providers;
+
+use App\Services\Auth\PasswordBrokerManager;
+use Illuminate\Auth\Passwords\PasswordResetServiceProvider as BasePasswordResetServiceProvider;
+
+class PasswordResetServiceProvider extends BasePasswordResetServiceProvider
+{
+    /**
+     * Register the password broker instance.
+     *
+     * @return void
+     */
+    protected function registerPasswordBroker()
+    {
+        $this->app->singleton('auth.password', function ($app) {
+            return new PasswordBrokerManager($app);
+        });
+
+        $this->app->bind('auth.password.broker', function ($app) {
+            return $app->make('auth.password')->broker();
+        });
+    }
+}

+ 3 - 6
app/Services/Auth/JwtGuard.php

@@ -90,13 +90,10 @@ class JwtGuard implements Guard
      */
     public function login(array $credentials)
     {
-        $token = $this->provider->retrieveByCredentials($credentials);
+        $user = $this->provider->retrieveByCredentials($credentials);
 
-        // If an implementation of UserInterface was returned, we'll ask the provider
-        // to validate the user against the given credentials, and if they are in
-        // fact valid we'll log the users into the application and return true.
-        if ($token) {
-            $user = $this->provider->retrieveByToken(null, $token);
+        $token = null;
+        if ($user && $token = $this->provider->validateCredentials($user, $credentials)) {
             $this->setUser($user);
         }
 

+ 21 - 17
app/Services/Auth/MicroUserProvider.php

@@ -88,46 +88,50 @@ class MicroUserProvider implements UserProvider
     /**
      * Retrieve a user by the given credentials.
      *
-     * @param  array $credentials
-     * @return string
+     * @param array $credentials
+     * @return UserItem|Authenticatable|null
+     * @throws AuthenticationException
      */
     public function retrieveByCredentials(array $credentials)
     {
-        if (empty($credentials) ||
+        if (empty($credentials) ||empty($credentials['email']) ||
             (count($credentials) === 1 &&
                 array_key_exists('password', $credentials))) {
-            return;
+            return null;
         }
 
         try {
-            $token = $this->userService->auth($credentials);
+            $user = $this->userService->getByEmail($credentials['email']);
         } catch (RpcException $exception) {
-            throw new AuthenticationException("认证失败:邮箱和密码不匹配");
+            throw new AuthenticationException("认证失败:对应邮箱尚未注册");
         }
 
-        return $token;
+        $model = $this->createModel();
+        $model->fillAttributes($user);
+        return $model;
     }
 
     /**
      * Validate a user against the given credentials.
      *
-     * @param  \Illuminate\Contracts\Auth\Authenticatable $user
-     * @param  array $credentials
+     * @param Authenticatable $user
+     * @param array $credentials
      * @return bool
+     * @throws AuthenticationException
      */
     public function validateCredentials(Authenticatable $user, array $credentials)
     {
-        if (empty($credentials['token'])) {
-            return false;
-        }
-
         try {
-            $valid = $this->userService->isAuth($credentials['token']);
+            if (empty($credentials['jwt_token'])) {
+                $token = $this->userService->auth($credentials);
+            } else {
+                $token = $this->userService->isAuth($credentials['jwt_token']);
+            }
         } catch (RpcException $exception) {
-            throw new AuthenticationException("认证失败:令牌失效,请重新认证");
+            $message = empty($credentials['jwt_token']) ? '注册邮箱与密码不匹配' : '令牌失效';
+            throw new AuthenticationException("认证失败:" . $message);
         }
-
-        return $valid;
+        return $token;
     }
 
     /**

+ 18 - 0
app/Services/Auth/PasswordBrokerManager.php

@@ -0,0 +1,18 @@
+<?php
+namespace App\Services\Auth;
+
+use Illuminate\Auth\Passwords\PasswordBrokerManager as BasePasswordBrokerManager;
+
+class PasswordBrokerManager extends BasePasswordBrokerManager
+{
+    /**
+     * Create a token repository instance based on the given configuration.
+     *
+     * @param  array  $config
+     * @return \Illuminate\Auth\Passwords\TokenRepositoryInterface
+     */
+    protected function createTokenRepository(array $config)
+    {
+        return new ServiceTokenRepository();
+    }
+}

+ 75 - 0
app/Services/Auth/ServiceTokenRepository.php

@@ -0,0 +1,75 @@
+<?php
+namespace App\Services\Auth;
+
+use App\MicroApi\Services\UserService;
+use Illuminate\Auth\Passwords\TokenRepositoryInterface;
+use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
+use Illuminate\Support\Str;
+
+class ServiceTokenRepository implements TokenRepositoryInterface
+{
+    /**
+     * @var UserService
+     */
+    protected $userService;
+
+    public function __construct()
+    {
+        $this->userService = resolve('microUserService');
+    }
+
+    /**
+     * Create a new token.
+     *
+     * @param  \Illuminate\Contracts\Auth\CanResetPassword $user
+     * @return string
+     */
+    public function create(CanResetPasswordContract $user)
+    {
+        $email = $user->getEmailForPasswordReset();
+
+        $key = config('app.key');
+        if (Str::startsWith($key, 'base64:')) {
+            $key = base64_decode(substr($key, 7));
+        }
+        $token = hash_hmac('sha256', Str::random(40), $key);
+
+        $payload = ['email' => $email, 'token' => $token];
+        $this->userService->createPasswordReset($payload);
+
+        return $token;
+    }
+
+    /**
+     * Determine if a token record exists and is valid.
+     *
+     * @param  \Illuminate\Contracts\Auth\CanResetPassword $user
+     * @param  string $token
+     * @return bool
+     */
+    public function exists(CanResetPasswordContract $user, $token)
+    {
+        return $this->userService->validatePasswordResetToken($token);
+    }
+
+    /**
+     * Delete a token record.
+     *
+     * @param  \Illuminate\Contracts\Auth\CanResetPassword $user
+     * @return void
+     */
+    public function delete(CanResetPasswordContract $user)
+    {
+        return $this->userService->deletePasswordReset($user->email);
+    }
+
+    /**
+     * Delete expired tokens.
+     *
+     * @return void
+     */
+    public function deleteExpired()
+    {
+        // TODO: Implement deleteExpired() method.
+    }
+}

+ 3 - 1
config/app.php

@@ -140,7 +140,7 @@ return [
         Illuminate\Pipeline\PipelineServiceProvider::class,
         Illuminate\Queue\QueueServiceProvider::class,
         Illuminate\Redis\RedisServiceProvider::class,
-        Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
+        //Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
         Illuminate\Session\SessionServiceProvider::class,
         Illuminate\Translation\TranslationServiceProvider::class,
         Illuminate\Validation\ValidationServiceProvider::class,
@@ -168,6 +168,8 @@ return [
         App\Providers\GlobalTemplateServiceProvider::class,
         App\Providers\RepositoryServiceProvider::class,
         Laratrust\LaratrustServiceProvider::class,
+
+        App\Providers\PasswordResetServiceProvider::class,
     ],
 
     /*

+ 5 - 1
config/auth.php

@@ -15,7 +15,7 @@ return [
 
     'defaults' => [
         'guard' => 'jwt',
-        'passwords' => 'users',
+        'passwords' => 'service',
     ],
 
     /*
@@ -124,6 +124,10 @@ return [
             'table' => 'password_resets',
             'expire' => 60,
         ],
+
+        'service' => [
+            'provider' => 'micro_user',
+        ]
     ],
 
 ];