由于业务系统使用keycloak做统一的认证,但论坛直接使用的phpwind。
用两套用户体系确实有点不太合适,特别是国情决定的实名制等。
如果在APP上搞定了用户注册加实名的话,那论坛使用APP的用户进行登录,理论上也是实现实名了。
代码是基于phpwind v9.1.0
,基础上的。
大概改不到10个文件,下面按照先后顺序依次说明。
1.开放平台接入设置
//ThirdOpenPlatformController.php 文件,可能会有两个
/**
* 显示在模板中的文本内容
*
* @access private
* @return void
*/
private function _displayText($type){
$_lab1 = array(
'AppId' =>'AppKey',
'AppKey'=>'AppSecret',
);
$_lab2 = array(
'AppId' =>'AppId',
'AppKey'=>'AppKey',
);
$_labs = array(
'taobao'=>$_lab1,
'weibo' =>$_lab1,
'weixin'=>$_lab2,
'qq' =>$_lab2,
'hifipi'=> $_lab2, //追加
);
return $_labs[$type];
}
2.Windid工具库
//WindidUtility.php 追加$htoken的处理,用于通过header['Authorization']传值,
public static function buildRequest($url, $params = array(), $isreturn = true, $timeout = 10, $method = 'post', $htoken = '') {
$request = Wind::getComponent('httptransfer', array($url, $timeout));
$request->setWaitResponse($isreturn);
if ($htoken != '') {
$request->setHeader($htoken, 'Authorization');
}
if ($method == 'post') {
if (!$params) $params = array('__data' => '1');//兼容部分版本post content不能为空的错误
return $request->post($params);
} else {
return $request->get($params);
}
}
3.登录
//PwThirdLoginService.php 追加针对oauth2认证的逻辑
// 追加hifipi的相关keycloak定义
public static $supportedPlatforms = array(
// See http://wiki.open.qq.com/wiki/website/%E4%BD%BF%E7%94%A8Authorization_Code%E8%8E%B7%E5%8F%96Access_Token
'qq' => array(
'img' => 'http://oss.aliyuncs.com/phpwind-image/4819ac3d87071089648af06c5fb7f204.png',
'authorize' => 'https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=%s&redirect_uri=%s&state=phpwind&scope=get_user_info',
'accesstoken' => 'https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&client_id=%s&client_secret=%s&code=%s&redirect_uri=%s',
'openid' => 'https://graph.qq.com/oauth2.0/me?access_token=%s',
'userinfo' => 'https://graph.qq.com/user/get_user_info?access_token=%s&oauth_consumer_key=%s&openid=%s',
'text' => '使用QQ帐号登录',
),
// See http://open.weibo.com/wiki/%E9%A6%96%E9%A1%B5
'weibo' => array(
'img' => 'http://oss.aliyuncs.com/phpwind-image/be7945e0d9521e74b8130a138b8694df.png',
'authorize' => 'https://api.weibo.com/oauth2/authorize?client_id=%s&redirect_uri=%s&scope=email&state=phpwind&display=default',
'accesstoken' => 'https://api.weibo.com/oauth2/access_token',
'userinfo' => 'https://api.weibo.com/2/users/show.json?access_token=%s&uid=%s',
'text' => '使用新浪微博帐号登录',
),
'hifipi'=>array(
'img' => 'http://auth.hifipi.com/auth/resources/3.3.0.final/admin/keycloak/img/keyclok-logo.png',
'authorize' => 'http://auth.hifipi.com/auth/realms/hifipi/protocol/openid-connect/auth?response_type=code&client_id=%s&redirect_uri=%s&state=phpwind&scope=get_user_info',
'accesstoken' => 'http://auth.hifipi.com/auth/realms/hifipi/protocol/openid-connect/token',
'userinfo' => 'http://auth.hifipi.com/auth/realms/hifipi/protocol/openid-connect/userinfo',
'text' => '使用HIFIPI帐号登录',
),
);
// 追加hifipi的auth处理
public function getAuthorizeUrl($platform)
{
$thirdPlatforms = Wekit::C('webThirdLogin');
$config = Wekit::C()->getConfigByName('site', 'info.url');
$redirecturl = $config['value'].'/index.php?m=u&c=login&a=thirdlogincallback&platform='.$platform;
switch($platform) {
case 'qq':
return sprintf(self::$supportedPlatforms[$platform]['authorize'],
$thirdPlatforms[$platform.'.appid'],
urlencode($redirecturl)
);
case 'weibo':
return sprintf(self::$supportedPlatforms[$platform]['authorize'],
$thirdPlatforms[$platform.'.appid'],
urlencode($redirecturl)
);
case 'hifipi':
return sprintf(self::$supportedPlatforms[$platform]['authorize'],
$thirdPlatforms[$platform.'.appid'],
urlencode($redirecturl)
);
default:
// should never happen
return '';
}
}
//追加hifipi的token处理,取到access_token就完事了
public function getAccessToken($platform, $authcode)
{
$thirdPlatforms = Wekit::C('webThirdLogin');
$config = Wekit::C()->getConfigByName('site', 'info.url');
$method = 'get';
$redirecturl = $config['value'].'/index.php?m=u&c=login&a=thirdlogincallback&platform='.$platform;
switch($platform) {
case 'qq':
$url = sprintf(self::$supportedPlatforms[$platform]['accesstoken'],
$thirdPlatforms[$platform.'.appid'],
$thirdPlatforms[$platform.'.appkey'],
$authcode,
urlencode($redirecturl)
);
break;
case 'weibo':
$url = self::$supportedPlatforms[$platform]['accesstoken'];
$postdata = array('client_id' => $thirdPlatforms[$platform.'.appid'],
'client_secret' => $thirdPlatforms[$platform.'.appkey'],
'code' => $authcode,
'redirect_uri' => $redirecturl,
);
$method = 'post';
break;
case 'hifipi':
$url = self::$supportedPlatforms[$platform]['accesstoken'];
$postdata = array('client_id' => $thirdPlatforms[$platform.'.appid'],
'grant_type' => 'authorization_code',
'client_secret' => $thirdPlatforms[$platform.'.appkey'],
'code' => $authcode,
'redirect_uri' => $redirecturl,
);
$method = 'post';
break;
default:
// should never happen
return array(false, '');
}
$data = $this->_request($url, ($method == 'post' ? $postdata : array()), $method);
if (!$data) {
return array(false, '');
}
switch($platform) {
case 'qq':
if (substr($data, 0, 8) == 'callback') {
$result = json_decode(substr($data, 10, -4), true);
} else {
parse_str($data, $result);
}
if (isset($result['error'])) {
return array(false, array($result['error'], $result['error_description']));
} else {
return array(true, $result['access_token'], 'extra' => array());
}
case 'weibo':
$result = json_decode($data, true);
if (isset($result['error_code']) && $result['error_code'] != 0) {
return array(false, array($result['error_code'], $result['error']));
}
return array(true, $result['access_token'], 'extra' => array('uid' => $result['uid']));
case 'hifipi':
$result = json_decode($data, true);
if (isset($result['error']) && $result['error'] != 0) {
return array(false, array($result['error'], $result['error_description']));
}
return array(true, $result['access_token'], 'extra' => array('uid' => $result['uid']));
default:
return array(false, '');
}
}
//取用户info,由于原代码有点长,这里省略了部分
public function getUserInfo($platform, $accesstoken, array $extra)
{
switch($platform) {
case 'qq':
$url = sprintf(self::$supportedPlatforms[$platform]['openid'],
$accesstoken
);
break;
default:
break;
}
if (isset($url)) {
$openid = $this->getOpenId($url);
if (!$openid[0]) {
return $openid;
}
$openid = $openid[1];
} else {
$openid = $extra['uid'];
}
$htoken = ''; //追加
$thirdPlatforms = Wekit::C('webThirdLogin');
switch($platform) {
case 'qq':
/////此处省略部分代码
case 'weibo':
/////此处省略部分代码
case 'hifipi':
$url = self::$supportedPlatforms[$platform]['userinfo'];
$htoken = 'bearer '.$accesstoken; //追加
break;
default:
break;
}
$data = $this->_request($url, array(), 'get', $htoken);
$userinfo = array();
switch($platform) {
case 'qq':
/////此处省略部分代码
case 'weibo':
/////此处省略部分代码
case 'hifipi':
$result = json_decode($data, true);
if (isset($result['error']) && $result['error'] != 0) {
$userinfo[0] = false;
$userinfo[1] = array('code' => $result['error'],
'msg' => $result['error_description']
);
} else {
$userinfo[0] = true;
$userinfo[1] = array(
'uid' => $result['sub'],
'username' => substr($result['preferred_username'], 0, 15),
//'gender' => $result['gender'] == 'm' ? 0 : 1,
//'avatar' => $result['avatar_large'],
'type' => $platform,
'email' => $result['email'],
);
}
return $userinfo;
default:
return array(false, '');
}
}
//追加了$htoken的参数
protected function _request($url, $params, $method = 'get', $htoken = '')
{
$result = WindidUtility::buildRequest($url, $params, /* isreturn = */ true,
self::HTTP_TIMEOUT, $method, $htoken);
return !empty($result) ? $result : false;
}
4.管理后台的画面
.....省略.....
//thirdopenplatform_run.htm
<ul class="cc">
<li {$typeClasses['qq']|html}><a href="{@url:config/ThirdOpenPlatform/run?type=qq}">QQ</a></li>
<li {$typeClasses['weibo']|html}><a href="{@url:config/ThirdOpenPlatform/run?type=weibo}">新浪微博</a></li>
<li {$typeClasses['hifipi']|html}><a href="{@url:config/ThirdOpenPlatform/run?type=hifipi}">Keycloak</a></li>
</ul>
.....省略.....
在后台及keycloak里配置好realm和client_id/client_secret,然后就可以使用keycloak的账号进行登录了。
具体效果,可以参考http://bbs.hifipi.com,刚建起来现在是测试(现在是连的测试用keycloak服务器),APP正在着手开发中。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。