由于业务系统使用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 happenreturn '';}
}
//追加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 happenreturn 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正在着手开发中。