记录
之前觉得问题都是出在
有些网站压根就没有使用
还发现
另外,还有一个问题,如果应用网站的处理是:校验了
示例代码如下(
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | $provider = new \League\OAuth2\Client\Provider\GenericProvider([ 'clientId' => 'XXXXXX', // The client ID assigned to you by the provider 'clientSecret' => 'XXXXXX', // The client password assigned to you by the provider 'redirectUri' => 'https://my.example.com/your-redirect-url/', 'urlAuthorize' => 'https://service.example.com/authorize', 'urlAccessToken' => 'https://service.example.com/token', 'urlResourceOwnerDetails' => 'https://service.example.com/resource' ]); // If we don't have an authorization code then get one if (!isset($_GET['code'])) { // Fetch the authorization URL from the provider; this returns the // urlAuthorize option and generates and applies any necessary parameters // (e.g. state). $authorizationUrl = $provider->getAuthorizationUrl(); // Get the state generated for you and store it to the session. $_SESSION['oauth2state'] = $provider->getState(); // Redirect the user to the authorization URL. header('Location: ' . $authorizationUrl); exit; // Check given state against previously stored one to mitigate CSRF attack } elseif (empty($_GET['state']) || (isset($_SESSION['oauth2state']) && $_GET['state'] !== $_SESSION['oauth2state'])) { if (isset($_SESSION['oauth2state'])) { unset($_SESSION['oauth2state']); } exit('Invalid state'); } else { try { // Try to get an access token using the authorization code grant. $accessToken = $provider->getAccessToken('authorization_code', [ 'code' => $_GET['code'] ]); // We have an access token, which we may use in authenticated // requests against the service provider's API. echo 'Access Token: ' . $accessToken->getToken() . "<br>"; echo 'Refresh Token: ' . $accessToken->getRefreshToken() . "<br>"; echo 'Expired in: ' . $accessToken->getExpires() . "<br>"; echo 'Already expired? ' . ($accessToken->hasExpired() ? 'expired' : 'not expired') . "<br>"; // Using the access token, we may look up details about the // resource owner. $resourceOwner = $provider->getResourceOwner($accessToken); var_export($resourceOwner->toArray()); // The provider provides a way to get an authenticated API request for // the service, using the access token; it returns an object conforming // to Psr\Http\Message\RequestInterface. $request = $provider->getAuthenticatedRequest( 'GET', 'https://service.example.com/resource', $accessToken ); } catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) { // Failed to get the access token or user details. exit($e->getMessage()); } } |
代码逻辑是:
- 先处理没有
code 参数的情况,也就是用户请求登录时,而不是从第三方认证网站重定向回来时 - 再处理
state 参数为空(包括没有state 参数和state 参数为'' 的情况),或者session 中有state 且提交的state 参数与session 中state 不相同的情况。这种情况就是认为不合法(此时为从第三方认证网站重定向回来时) - 最后处理的就是合法情况(此时为从第三方认证网站重定向回来时)
但是如果是这样的情况:受害者未曾请求过绑定第三方账号,那么
在这样的情况下,服务器端没有与受害者对应的
所以应当在上述第三步之前再增加一步校验当前
Server端代码修改
我需要模拟现在的很多
检查的代码在
创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /* OAuth server相关配置 */ $dsn = "mysql:dbname=$db_name;host=$host"; // $dsn = 'mysql:dbname=thinkphp;host=127.0.0.1'; \OAuth2\Autoloader::register(); // $dsn is the Data Source Name for your database, for exmaple "mysql:dbname=my_oauth2_db;host=localhost" $storage = new \OAuth2\Storage\Pdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password)); $config = ['enforce_state' => false]; // Pass a storage object or array of storage objects to the OAuth2 server class $server = new \OAuth2\Server($storage, $config); // 在此处传递$config参数即可 // Add the "Client Credentials" grant type (it is the simplest of the grant types) $server->addGrantType(new \OAuth2\GrantType\ClientCredentials($storage)); // Add the "Authorization Code" grant type (this is where the oauth magic happens) $server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($storage)); |