├── src ├── Interfaces │ └── PhoneVerificationCodeGrantUserInterface.php ├── PhoneVerificationCodeGrantServiceProvider.php ├── Bridge │ └── UserRepository.php └── PhoneVerificationCodeGrant.php ├── phpunit.xml.dist ├── composer.json ├── LICENSE.txt ├── README-zh-CN.md └── README.md /src/Interfaces/PhoneVerificationCodeGrantUserInterface.php: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | 19 | 20 | ./src/ 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "qiutuleng/laravel-passport-phone-verification-code-grant", 3 | "description": "Resource owner phone verification code credentials grant for Laravel Passport", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Qiu Tuleng", 8 | "email": "qiutuleng@gmail.com" 9 | } 10 | ], 11 | "require": { 12 | "php": ">=5.6.4", 13 | "laravel/passport": "*" 14 | }, 15 | "autoload": { 16 | "psr-4": { 17 | "QiuTuleng\\PhoneVerificationCodeGrant\\": "src/" 18 | } 19 | }, 20 | "extra": { 21 | "laravel": { 22 | "providers": [ 23 | "QiuTuleng\\PhoneVerificationCodeGrant\\PhoneVerificationCodeGrantServiceProvider" 24 | ] 25 | } 26 | }, 27 | "minimum-stability": "dev" 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /src/PhoneVerificationCodeGrantServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->resolving(AuthorizationServer::class, function (AuthorizationServer $server) { 21 | $server->enableGrantType($this->makeVerificationCodeGrant(), Passport::tokensExpireIn()); 22 | }); 23 | } 24 | 25 | protected function makeVerificationCodeGrant() 26 | { 27 | $grant = new PhoneVerificationCodeGrant( 28 | $this->app->make(UserRepository::class), 29 | $this->app->make(RefreshTokenRepository::class) 30 | ); 31 | 32 | $grant->setRefreshTokenTTL(Passport::refreshTokensExpireIn()); 33 | 34 | return $grant; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Bridge/UserRepository.php: -------------------------------------------------------------------------------- 1 | findOrCreateForPassportVerifyCodeGrant($phoneNumber); 35 | 36 | if (!$user || !$user->validateForPassportVerifyCodeGrant($verificationCode)) { 37 | return; 38 | } 39 | 40 | return new User($user->getAuthIdentifier()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /README-zh-CN.md: -------------------------------------------------------------------------------- 1 | # Laravel Passport Phone Verification Code Grant 2 | 3 | ## 介绍 4 | 5 | 基于Laravel Passport的手机验证码授权 6 | 7 | ## 安装 8 | 9 | 进入到你的项目目录,然后运行以下命令 10 | 11 | ```bash 12 | composer require qiutuleng/laravel-passport-phone-verification-code-grant 13 | ``` 14 | 15 | ## 设置 16 | 17 | ### Laravel 18 | 19 | 如果你的Laravel版本大于等于`5.5`,服务提供者将会自动注册到程序中。 20 | 21 | 其他版本你需要把`\QiuTuleng\PhoneVerificationCodeGrant\PhoneVerificationCodeGrantServiceProvider::class`添加到`config/app.php`中的`providers`属性中。 22 | 23 | ```php 24 | 'providers' => [ 25 | /* 26 | * Package Service Providers... 27 | */ 28 | ... 29 | \QiuTuleng\PhoneVerificationCodeGrant\PhoneVerificationCodeGrantServiceProvider::class, 30 | ] 31 | ``` 32 | 33 | ### Lumen 34 | 35 | 你可以在`app/Providers/AppServiceProvider.php`的`register`函数中添加以下代码注册服务提供者。 36 | 37 | ```php 38 | $app->register(\QiuTuleng\PhoneVerificationCodeGrant\PhoneVerificationCodeGrantServiceProvider::class); 39 | ``` 40 | 41 | ## 如何使用? 42 | 43 | ### 配置 44 | 45 | 1. 你必须在 `User` Model中实现 `\QiuTuleng\PhoneVerificationCodeGrant\Interfaces\PhoneVerificationCodeGrantUserInterface` 接口。 46 | 47 | ```php 48 | $phoneNumber]); 76 | 77 | // If the phone number is not exists in users table, will be fail to authenticate. 78 | // return static::where('mobile', '=', $phoneNumber)->first(); 79 | } 80 | 81 | /** 82 | * Check the verification code is valid. 83 | * 84 | * @param $verificationCode 85 | * @return boolean 86 | */ 87 | public function validateForPassportVerifyCodeGrant($verificationCode) 88 | { 89 | // Check verification code is valid. 90 | // return \App\Code::where('mobile', $this->mobile)->where('code', '=', $verificationCode)->where('expired_at', '>', now()->toDatetimeString())->exists(); 91 | return true; 92 | } 93 | ``` 94 | 95 | 3. (可选) 你还可以在配置文件中重命名 `phone_number` 和 `verification_code` 字段: 96 | 97 | 为此,请在“config/passport.php”中添加字段,例如: 98 | 99 | ```php 100 | //... 101 | 'phone_verification' => [ 102 | 'phone_number_request_key' => 'phone', 103 | 'verification_code_request_key' => 'verification_code', 104 | ], 105 | //... 106 | ``` 107 | 108 | 109 | ### 请求Token 110 | 111 | 你可以使用`POST`方式访问`/oautn/token`接口来获取Token,具体请求参数参照以下代码。 112 | 113 | ```php 114 | $http = new GuzzleHttp\Client; 115 | 116 | $response = $http->post('http://your-app.com/oauth/token', [ 117 | 'form_params' => [ 118 | 'grant_type' => 'phone_verification_code', 119 | 'client_id' => 'client-id', 120 | 'client_secret' => 'client-secret', 121 | 'phone_number' => '+8613416292625', 122 | 'verification_code' => 927068, 123 | 'scope' => '', 124 | ], 125 | ]); 126 | 127 | return json_decode((string) $response->getBody(), true); 128 | ``` 129 | 130 | ## 更多 131 | 132 | 你可以访问 [Laravel/Passport](https://laravel.com/docs/master/passport) 官方文档来了解更多信息。 133 | 134 | ## 贡献 135 | 136 | 你可以在此仓库中创建一个 [pull requests](https://github.com/qiutuleng/vue-router-modern/pulls) 。 137 | 138 | 期待你的想法或代码。 139 | 140 | ## Issues 141 | 142 | 如果你有任何问题,请在 [Issues](https://github.com/qiutuleng/vue-router-modern/issues) 中提出,我将会尽力为你解决。 143 | -------------------------------------------------------------------------------- /src/PhoneVerificationCodeGrant.php: -------------------------------------------------------------------------------- 1 | setUserRepository($userRepository); 27 | $this->setRefreshTokenRepository($refreshTokenRepository); 28 | 29 | $this->refreshTokenTTL = new \DateInterval('P1M'); 30 | } 31 | 32 | /** 33 | * Respond to an incoming request. 34 | * 35 | * @param ServerRequestInterface $request 36 | * @param ResponseTypeInterface $responseType 37 | * @param \DateInterval $accessTokenTTL 38 | * 39 | * @return ResponseTypeInterface 40 | */ 41 | public function respondToAccessTokenRequest( 42 | ServerRequestInterface $request, 43 | ResponseTypeInterface $responseType, 44 | \DateInterval $accessTokenTTL 45 | ) 46 | { 47 | // Validate request 48 | $client = $this->validateClient($request); 49 | $scopes = $this->validateScopes($this->getRequestParameter('scope', $request, $this->defaultScope)); 50 | $user = $this->validateUser($request, $client); 51 | 52 | // Finalize the requested scopes 53 | $finalizedScopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $user->getIdentifier()); 54 | 55 | // Issue and persist new tokens 56 | $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $finalizedScopes); 57 | $refreshToken = $this->issueRefreshToken($accessToken); 58 | 59 | // Inject tokens into response 60 | $responseType->setAccessToken($accessToken); 61 | $responseType->setRefreshToken($refreshToken); 62 | 63 | return $responseType; 64 | } 65 | 66 | /** 67 | * @param ServerRequestInterface $request 68 | * @param ClientEntityInterface $client 69 | * 70 | * @throws OAuthServerException 71 | * 72 | * @return UserEntityInterface 73 | */ 74 | protected function validateUser(ServerRequestInterface $request, ClientEntityInterface $client) 75 | { 76 | $requestPhoneNumberKey = config('passport.phone_verification.phone_number_request_key', 'phone_number'); 77 | $phoneNumber = $this->getRequestParameter($requestPhoneNumberKey, $request); 78 | if (is_null($phoneNumber)) { 79 | throw OAuthServerException::invalidRequest($requestPhoneNumberKey); 80 | } 81 | 82 | $requestVerificationCode = config('passport.phone_verification.verification_code_request_key', 'verification_code'); 83 | $verificationCode = $this->getRequestParameter($requestVerificationCode, $request); 84 | if (is_null($verificationCode)) { 85 | throw OAuthServerException::invalidRequest($requestVerificationCode); 86 | } 87 | 88 | $user = $this->userRepository->getUserEntityByUserCredentials( 89 | $phoneNumber, 90 | $verificationCode, 91 | $this->getIdentifier(), 92 | $client 93 | ); 94 | if ($user instanceof UserEntityInterface === false) { 95 | $this->getEmitter()->emit(new RequestEvent(RequestEvent::USER_AUTHENTICATION_FAILED, $request)); 96 | 97 | throw OAuthServerException::invalidCredentials(); 98 | } 99 | 100 | return $user; 101 | } 102 | 103 | /** 104 | * Return the grant identifier that can be used in matching up requests. 105 | * 106 | * @return string 107 | */ 108 | public function getIdentifier() 109 | { 110 | return 'phone_verification_code'; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Passport Phone Verification Code Grant 2 | 3 | ## Introduction 4 | 5 | Resource owner phone verification code credentials grant for Laravel Passport 6 | 7 | [中文文档 / Chinese document](./README-zh-CN.md) 8 | 9 | ## Install 10 | 11 | Under your working folder and run the command in terminal: 12 | 13 | ```bash 14 | composer require qiutuleng/laravel-passport-phone-verification-code-grant 15 | ``` 16 | 17 | ## Setup 18 | 19 | ### Laravel 20 | 21 | If your laravel version is greater or equal to `5.5`, the service provider will be attached automatically. 22 | 23 | Other versions, you must needs add `\QiuTuleng\PhoneVerificationCodeGrant\PhoneVerificationCodeGrantServiceProvider::class` to the `providers` array in `config/app.php`: 24 | 25 | ```php 26 | 'providers' => [ 27 | /* 28 | * Package Service Providers... 29 | */ 30 | ... 31 | \QiuTuleng\PhoneVerificationCodeGrant\PhoneVerificationCodeGrantServiceProvider::class, 32 | ] 33 | ``` 34 | 35 | ### Lumen 36 | 37 | ```php 38 | $app->register(\QiuTuleng\PhoneVerificationCodeGrant\PhoneVerificationCodeGrantServiceProvider::class); 39 | ``` 40 | 41 | ## How to use? 42 | 43 | ### Configure 44 | 45 | 1. You must needs implement `\QiuTuleng\PhoneVerificationCodeGrant\Interfaces\PhoneVerificationCodeGrantUserInterface` interface in your `User` model. 46 | 47 | ```php 48 | $phoneNumber]); 76 | 77 | // If the phone number is not exists in users table, will be fail to authenticate. 78 | // return static::where('mobile', '=', $phoneNumber)->first(); 79 | } 80 | 81 | /** 82 | * Check the verification code is valid. 83 | * 84 | * @param $verificationCode 85 | * @return boolean 86 | */ 87 | public function validateForPassportVerifyCodeGrant($verificationCode) 88 | { 89 | // Check verification code is valid. 90 | // return \App\Code::where('mobile', $this->mobile)->where('code', '=', $verificationCode)->where('expired_at', '>', now()->toDatetimeString())->exists(); 91 | return true; 92 | } 93 | ``` 94 | 95 | 3. (Optional) Also you can rename `phone_number` and `verification_code` fields in config file: 96 | 97 | To do this, add keys in `config/passport.php`, example: 98 | 99 | ```php 100 | //... 101 | 'phone_verification' => [ 102 | 'phone_number_request_key' => 'phone', 103 | 'verification_code_request_key' => 'verification_code', 104 | ], 105 | //... 106 | ``` 107 | 108 | 109 | ### Request Tokens 110 | 111 | You may request an access token by issuing a `POST` request to the `/oauth/token` route with the user's phone number and verification code. 112 | 113 | ```php 114 | $http = new GuzzleHttp\Client; 115 | 116 | $response = $http->post('http://your-app.com/oauth/token', [ 117 | 'form_params' => [ 118 | 'grant_type' => 'phone_verification_code', 119 | 'client_id' => 'client-id', 120 | 'client_secret' => 'client-secret', 121 | 'phone_number' => '+8613416292625', 122 | 'verification_code' => 927068, 123 | 'scope' => '', 124 | ], 125 | ]); 126 | 127 | return json_decode((string) $response->getBody(), true); 128 | ``` 129 | 130 | ## More 131 | 132 | You can check out the [Laravel/Passport](https://laravel.com/docs/master/passport) official documentation to learn more 133 | 134 | ## Contributing 135 | 136 | You can create a [pull requests](https://github.com/qiutuleng/vue-router-modern/pulls) to this repository. 137 | 138 | Welcome your ideas or code. 139 | 140 | ## Issues 141 | 142 | If you have any questions, please ask your question in the [Issues](https://github.com/qiutuleng/vue-router-modern/issues) and I will try my best to help you. 143 | --------------------------------------------------------------------------------