前言:
OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版。国内的新浪,百度,QQ登录,微信登录等等都是运用的该协议。目前需要在其他正在开发的项目中使用另一个项目的账号来作为登录账号,那么就需要运用这个协议来实现。
一、选择使用OAuth2 的简述:
在前阵子开发陪练订单系统和打赏系统,由于考虑到交易的安全的性,就考虑到了token(令牌)的问题,因此查询了关于OAuth2的一些资料就找了关于OAuth2 Server PHP 来实现OAuth2 Server的扩展程序。
二、下载地址:下载
三、查遍了网上各种文档,技术文章,基本都是使用Authorization_code(授权码的方式)与目前项目需求有差别,下面我这边使用的是密码的方式,并且使用redis进行存储token数据
在服务器端新建了一个类工具代码:TokenUtil 类,MyRedis类,这里也用到Predis类库,可从这个地址下载:下载,若使用composer就跟方便了
TokenUtil 类:
<?php
/**
* Created by PhpStorm.
* User: wyb
* Date: 2017/11/28
*/
namespace Common\Tools;
use OAuth2\GrantType\RefreshToken;
use OAuth2\GrantType\UserCredentials;
use OAuth2\Request;
use OAuth2\Response;
use OAuth2\Scope;
use OAuth2\Server;
use OAuth2\Storage\Memory;
class TokenUtil {
public $codeMsg=[];
/**
* 获取token
* @return array
*/
public function getToken()
{
$server = $this->getServer();
/** @var Response $response */
$response = $server->handleTokenRequest(Request::createFromGlobals());
$result = $response->getParameters();
$result['statusCode'] =$response->getStatusCode();
return $result;
}
/**
* 刷新token
* @return array
*/
public function refresh()
{
$server = $this->getServer();
$response = $server->handleTokenRequest(Request::createFromGlobals());
/** @var Response $response */
$result = $response->getParameters();
$result['statusCode'] =$response->getStatusCode();
return $result;
}
/**
* 判断是否可以获取资源
* @return array 成功返回token里面的用户id,失败返回失败信息
*/
public function resource()
{
$server = $this->getServer();
$_POST['client_id']=$server->getStorage('user_credentials')->clientId;
$_POST['client_secret']=$server->getStorage('user_credentials')->clientSecret;
// Handle a request to a resource and authenticate the access token
$flag=$server->verifyResourceRequest(Request::createFromGlobals());
$response = $server->getResponse();
if ( !$flag ) {
$result = $response->getParameters();
$result['statusCode'] =$response->getStatusCode();
}else{
$token = $server->getAccessTokenData(Request::createFromGlobals());
$result['statusCode'] =$response->getStatusCode();
$result['member_id'] =$token['user_id'];
}
return $result;
}
/**
* 获取一个Oauth对象,里面设置范围;两种授权方式password,refresh_token
* @return Server
*/
private function getServer()
{
$redis = new Predis(6);
$storage = new MyRedis($redis->getClient());
//$storage->setClientDetails('testclient','testpass');
// Pass a storage object or array of storage objects to the OAuth2 server class
//设置刷新token,同时设置时间过期为28天
$server = new Server($storage, array(
'refresh_token_lifetime' => 2419200,
'access_lifetime' => 7200,//调试开启60秒
));
//范围
$defaultScope = 'basic';
$memory = new Memory(array('default_scope' => $defaultScope));
$scopeUtil = new Scope($memory);
$server->setScopeUtil($scopeUtil);
$grantType = new UserCredentials($storage);
$grantType1 = new RefreshToken($storage, array(
'always_issue_new_refresh_token' => false
));
// add the grant type to your OAuth server
$server->addGrantType($grantType);
$server->addGrantType($grantType1);
return $server;
}
}
MyRedis类:(具体内容根据你自己需求)
<?php
namespace Common\Tools;
use Common\Model\MemberModel;
use OAuth2\Storage\Redis;
class MyRedis extends Redis {
public $clientId='xxx';
public $clientSecret='xxxxx';
public function setUser($username, $password, $first_name = null, $last_name = null)
{
return $this->setValue(
$this->config['user_key'] . $username,
compact('username', 'password', 'first_name', 'last_name'),
86400+time()
);
}
public function getUser($username)
{
//先判断redis有没有保存这个用户,有直接返回
$user = parent::getUser($username);
if (!empty($user)) {
return $user;
}
//第二步redis不存在,去数据查找,如果找到保存到redis下,否则返回false
$model= new MemberModel();
$member=$model->find($username);
if (empty($member)) {
return false;
}else{
$this->setUser($username,'');
}
// the default behavior is to use "username" as the user_id
return array_merge(array(
'user_id' => $username,
), $member);
}
public function checkUserCredentials($username, $password)
{
$user = $this->getUserDetails($username);
return $user?true:false;
}
public function getUserDetails($username)
{
return $this->getUser($username);
}
public function checkClientCredentials($client_id, $client_secret = null)
{
if ($client_id!=$this->clientId) {
return false;
}
return ( $this->clientSecret == $client_secret);
}
}