最新的,支持 check_authentication 验证

演示地址:http://www.freebapp.org/tools/openid/

参考:
上一次的版本

OpenID登陆!
Yahoo的OpenID登陆
Windows Live ID当作OpenID使用的方法
Google的OpenID的登陆

<?php
error_reporting(0);
//ini_set('error_reporting', E_ALL);
//ini_set("display_errors", 1);

$LoginUrl = 'http://freebapp.org/tools/openid/';
$AuthUrl = 'http://freebapp.org/tools/openid/auth.php';
$RealmUrl = 'http://freebapp.org/';
$PolicyUrl = 'http://freebapp.org/policy_url.html';

if(!empty($_REQUEST['AuthType'])){
	$AuthType = $_REQUEST['AuthType'];
	setcookie('cookieAuthType', $AuthType);
}else{
	if(!empty($_COOKIE['cookieAuthType'])){
		$AuthType = $_COOKIE['cookieAuthType'];
	}else{
		LocationHtml($LoginUrl);
	}
}

if(!empty($_REQUEST['return_to'])){
	$ReturnToUrl = $_REQUEST['return_to'];
	setcookie('cookieReturnTo', $ReturnToUrl);
}else{
	if(!empty($_COOKIE['cookieReturnTo'])){
		$ReturnToUrl = $_COOKIE['cookieReturnTo'];
	}else{
		$ReturnToUrl = $RealmUrl;
	}
}
/*
if(!empty($_COOKIE['cookieAssocHandle'])){
	$AssocHandle = $_COOKIE['cookieAssocHandle'];
}else{
	$AssocHandle = null;
}
*/
switch($AuthType){
	case 'Google':
		if(empty($_REQUEST['openid_mode'])){
			$openid_server = getXrdsUri('https://www.google.com/accounts/o8/id');
			$data['openid.ns'] = 'http://specs.openid.net/auth/2.0';
			$data['openid.mode'] = 'associate';
			$data['openid.assoc_type'] = 'HMAC-SHA1';
			$data['openid.session_type'] = 'DH-SHA1';
			$AssocHandle = getAssociationHandle($openid_server.'?'.http_build_query($data));
			//setcookie('cookieAssocHandle', $AssocHandle);
			unset($data);

			$data['openid.ns'] = 'http://specs.openid.net/auth/2.0';
			$data['openid.claimed_id'] = 'http://specs.openid.net/auth/2.0/identifier_select';
			$data['openid.identity'] = 'http://specs.openid.net/auth/2.0/identifier_select';
			$data['openid.return_to'] = $AuthUrl;
			$data['openid.realm'] = $RealmUrl;
			$data['openid.assoc_handle'] = $AssocHandle;
			$data['openid.mode'] = 'checkid_setup';

			$data['openid.ns.pape'] = 'http://specs.openid.net/extensions/pape/1.0';
			$data['openid.ns.max_auth_age'] = 0;

			$data['openid.ns.ax'] = 'http://openid.net/srv/ax/1.0';
			$data['openid.ax.mode'] = 'fetch_request';
			$data['openid.ax.type.country'] = 'http://axschema.org/contact/country/home';
			$data['openid.ax.type.email'] = 'http://axschema.org/contact/email';
			$data['openid.ax.type.firstname'] = 'http://axschema.org/namePerson/first';
			$data['openid.ax.type.language'] = 'http://axschema.org/pref/language';
			$data['openid.ax.type.lastname'] = 'http://axschema.org/namePerson/last';
			$data['openid.ax.required'] = 'country,email,firstname,language,lastname';

			$LocationUrl  = $openid_server.'?'.http_build_query($data);
		}else{
			if('id_res' == $_REQUEST['openid_mode']){
				$openid_server = $_REQUEST['openid_op_endpoint'];
				$openid_signed = getAuthenticationSigned($_REQUEST);
				if(getAuthentication($openid_server, http_build_query($openid_signed))){
					$openid = formUrl($_REQUEST['openid_claimed_id']);
					$email = !empty($_REQUEST['openid_ax_value_email']) ? $_REQUEST['openid_ax_value_email'] : $_REQUEST['openid_ext1_value_email'];
					$fullname = (!empty($_REQUEST['openid_ax_value_lastname']) ? $_REQUEST['openid_ax_value_lastname'] : $_REQUEST['openid_ext1_value_lastname']).' '.(!empty($_REQUEST['openid_ax_value_firstname']) ? $_REQUEST['openid_ax_value_firstname'] : $_REQUEST['openid_ext1_value_firstname']);
					$nickname = !empty($_REQUEST['openid_ax_value_lastname']) ? $_REQUEST['openid_ax_value_lastname'] : $_REQUEST['openid_ext1_value_lastname'];
				}else{
					echo('<pre>');
					echo("<a href=$LoginUrl>BACK</a>\n\n");
					echo('Error!');
					echo('</pre>');
					exit;
				}
			}
		}
		break;
	case 'Yahoo':
		if(empty($_REQUEST['openid_mode'])){
			$openid_server = 'https://open.login.yahooapis.com/openid/op/auth';
			$data['openid.ns'] = 'http://specs.openid.net/auth/2.0';
			$data['openid.mode'] = 'associate';
			$data['openid.assoc_type'] = 'HMAC-SHA1';
			$data['openid.session_type'] = 'DH-SHA1';
			$AssocHandle = getAssociationHandle($openid_server.'?'.http_build_query($data));
			//setcookie('cookieAssocHandle', $AssocHandle);
			unset($data);

			$data['openid.ns'] = 'http://specs.openid.net/auth/2.0';
			$data['openid.claimed_id'] = 'http://specs.openid.net/auth/2.0/identifier_select';
			$data['openid.identity'] = 'http://specs.openid.net/auth/2.0/identifier_select';
			$data['openid.return_to'] = $AuthUrl;
			$data['openid.realm'] = $RealmUrl;
			$data['openid.assoc_handle'] = $AssocHandle;
			$data['openid.mode'] = 'checkid_setup';

			$data['openid.ns.pape'] = 'http://specs.openid.net/extensions/pape/1.0';
			$data['openid.ns.max_auth_age'] = 0;

			$data['openid.ns.ax'] = 'http://openid.net/srv/ax/1.0';
			$data['openid.ax.mode'] = 'fetch_request';
			$data['openid.ax.type.country'] = 'http://axschema.org/contact/country/home';
			$data['openid.ax.type.email'] = 'http://axschema.org/contact/email';
			$data['openid.ax.type.firstname'] = 'http://axschema.org/namePerson/first';
			$data['openid.ax.type.language'] = 'http://axschema.org/pref/language';
			$data['openid.ax.type.lastname'] = 'http://axschema.org/namePerson/last';
			$data['openid.ax.required'] = 'country,email,firstname,language,lastname';
			$data['xopenid.lang.pref'] = 'tw';

			$LocationUrl  = $openid_server.'?'.http_build_query($data);
		}else{
			if('id_res' == $_REQUEST['openid_mode']){
				$openid_server = $_REQUEST['openid_op_endpoint'];
				$openid_signed = getAuthenticationSigned($_REQUEST);
				if(getAuthentication($openid_server, http_build_query($openid_signed))){
					$openid = !empty($_REQUEST['openid_identity']) ? formUrl($_REQUEST['openid_identity']) : formUrl($_REQUEST['openid_claimed_id']);
					$email = $_REQUEST['openid_ax_value_email'];
					$fullname = (!empty($_REQUEST['openid_ax_value_lastname']) ? $_REQUEST['openid_ax_value_lastname'] : $_REQUEST['openid_ext1_value_lastname']).' '.(!empty($_REQUEST['openid_ax_value_firstname']) ? $_REQUEST['openid_ax_value_firstname'] : $_REQUEST['openid_ext1_value_firstname']);
					$nickname = !empty($_REQUEST['openid_ax_value_lastname']) ? $_REQUEST['openid_ax_value_lastname'] : $_REQUEST['openid_ext1_value_lastname'];
					$timezone = $_REQUEST['openid_ax_value_timezone'];
				}else{
					echo('<pre>');
					echo("<a href=$LoginUrl>BACK</a>\n\n");
					echo('Error!');
					echo('</pre>');
					exit;
				}
			}
		}
		break;
	case 'Live':
		$DEBUG = true;
		$KEYFILE = './Live/Application-Key.xml';
		$COOKIE = 'webauthtoken';
		$COOKIETTL = time() + (10 * 365 * 24 * 60 * 60);

		include_once('./Live/lib/windowslivelogin.php');
		$wll = WindowsLiveLogin::initFromXml($KEYFILE);
		$wll->setDebug($DEBUG);

		if(!empty($_REQUEST['action'])){
			switch($_REQUEST['action']) {
				case 'logout':
					setcookie($COOKIE);
					$LocationUrl = $RealmUrl;
					break;
				case "clearcookie":
					setcookie($COOKIE);
					$LocationUrl = $AuthUrl;
					break;
				default:
					$user = $wll->processConsent($_REQUEST);
					if(!empty($user)){
						setcookie($COOKIE, $user->getToken(), $COOKIETTL);
						$LocationUrl = $AuthUrl;
					}else{
						$LocationUrl = $LoginUrl;
					}
					break;
			}
			LocationHtml($LocationUrl);
		}
		$token = $_COOKIE[$COOKIE];
		if($token){
			$user = $wll->processConsentToken($token);
			if(!$user->isValid()){
				$LocationUrl = $AuthUrl.'?AuthType=Live&action=clearcookie';
			}else{
				$url = 'https://livecontacts.services.live.com/users/@L@'.$user->getLocationID().'/rest/livecontacts/owner';
				$owner = getLiveID($url, array('Authorization: DelegatedToken dt="'.$user->getDelegationToken().'"'));
				$openid = $owner->WindowsLiveID.' | http://cid-'.$user->getLocationID().'.profile.live.com/';
				$email = $owner->WindowsLiveID;
				$fullname = $owner->Profiles->Personal->LastName.' '.$owner->Profiles->Personal->FirstName;
				$nickname = $owner->Profiles->Personal->DisplayName;
				echo('<pre>');
				echo("<a href=$LoginUrl>BACK</a>\n\n");
				print_r($owner);
				echo('</pre>');
			}
		}else{
			$LocationUrl = $wll->getConsentUrl('Contacts.View', 'zh-CN');
		}
		break;
	case 'OpenID':
		if(empty($_REQUEST['openid_mode'])){
			if(empty($_REQUEST['OpenID']))
				LocationHtml($LoginUrl, 'OpenID is null!');
			$openid_url = formUrl($_REQUEST['OpenID']);
			$openid_server_list = getOpenIDServer($openid_url);
			if(empty($openid_server_list))
				LocationHtml($LoginUrl, 'OpenID server is null!');

			if(!empty($openid_server_list[1]))
				$openid_server = $openid_server_list[1];
			if(!empty($openid_server_list[2]))
				$openid_server = $openid_server_list[2];
			if(!empty($openid_server_list[3]))
				$openid_url = $openid_server_list[3];
			$data['openid.ns'] = 'http://specs.openid.net/auth/2.0';
			$data['openid.mode'] = 'associate';
			$data['openid.assoc_type'] = 'HMAC-SHA1';
			$data['openid.session_type'] = 'DH-SHA1';
			$AssocHandle = getAssociationHandle($openid_server.'?'.http_build_query($data));
			setcookie('cookieAssocHandle', $AssocHandle);
			unset($data);

			$data['openid.assoc_handle'] = $AssocHandle;
			$data['openid.claimed_id'] = $openid_url;
			$data['openid.identity'] = $openid_url;
			$data['openid.mode'] = 'checkid_setup';
			$data['openid.ns'] = 'http://specs.openid.net/auth/2.0';
			$data['openid.ns.sreg'] = 'http://openid.net/extensions/sreg/1.1';
			$data['openid.realm'] = $RealmUrl;
			$data['openid.return_to'] = $AuthUrl;
			$data['openid.sreg.optional'] = 'nickname,email,fullname,dob,gender,postcode,country,language,timezone';
			$data['openid.sreg.policy_url'] = $PolicyUrl;
			$data['openid.sreg.required'] = 'email';
			$data['openid.trust_root'] = $RealmUrl;

			$LocationUrl  = $openid_server.'?'.http_build_query($data);
		}else{
			if('id_res' == $_REQUEST['openid_mode']){
				$openid_server = $_REQUEST['openid_op_endpoint'];
				$openid_signed = getAuthenticationSigned($_REQUEST);
				if(getAuthentication($openid_server, http_build_query($openid_signed))){
					$openid = !empty($_REQUEST['openid_claimed_id']) ? formUrl($_REQUEST['openid_claimed_id']) : formUrl($_REQUEST['openid_identity']);
					$email = $_REQUEST['openid_sreg_email'];
					$fullname = $_REQUEST['openid_sreg_fullname'];
					$nickname = $_REQUEST['openid_sreg_nickname'];
					$timezone = $_REQUEST['openid_sreg_timezone'];
				}else{
					echo('<pre>');
					echo("<a href=$LoginUrl>BACK</a>\n\n");
					echo('Error!');
					echo('</pre>');
					exit;
				}
			}
		}
		break;
	default:
		LocationHtml($LoginUrl);
}

if(empty($openid))
	LocationHtml($LocationUrl);

echo('<pre>');
echo("<a href=$LoginUrl>BACK</a>\n\n");
print_r($_REQUEST);
echo('</pre>');

echo('<pre>');
echo("openid  : $openid\n");
echo("email   : $email\n");
echo("fullname: $fullname\n");
echo("nickname: $nickname\n");
echo("timezone: $timezone\n");
echo('</pre>');

function getLiveID($url, $header){
	$d = getCurl($url, '', $header);
	if(200 != $d['header']['http_code']){
		return false;
	}

	try{
		$xml = new SimpleXMLElement($d['data']);
	}catch(Exception $e){
		return false;
	}
	return $xml;
}

function getOpenIDServer($url){
	$d = getCurl($url);
	if(200 != $d['header']['http_code']){
		return false;
	}

	$s = array();
	preg_match("/\<link rel=\"openid\.server\" href=\"([^\"]+)\"( )?(\/)?\>/i", $d['data'], $matches);
	if(!empty($matches))
		$s[1] = $matches[1];
	preg_match("/\<link rel=\"openid2\.provider\" href=\"([^\"]+)\"( )?(\/)?\>/i", $d['data'], $matches);
	if(!empty($matches))
		$s[2] = $matches[1];
	preg_match("/\<link rel=\"openid\.delegate\" href=\"([^\"]+)\"( )?(\/)?\>/i", $d['data'], $matches);
	if(!empty($matches))
		$s[3] = $matches[1];
	return $s;
}

function formUrl($url){
	$urls = parse_url($url);
	$scheme = 'http';
	if(empty($urls['scheme']))
		$urls = parse_url($scheme.'://'.$url);
	else
		$scheme = $urls['scheme'];
	if(empty($urls['host']))
		$host = '';
	else
		$host = $urls['host'];
	if(empty($urls['path']))
		$path = '/';
	else
		$path = $urls['path'];
	if('/' != $path){
		$path = ereg_replace('/$', '', $path);
	}
	if(empty($urls['query']))
		$query = '';
	else
		$query = '?'.$urls['query'];
	return strtolower($scheme.'://'.$host).$path.$query;
}

function getXrdsUri($url){
	$d = getCurl($url);
	if(200 != $d['header']['http_code']){
		return '';
	}

	$domdoc = new DOMDocument();
	$domdoc->loadXML($d['data']);

	$uri = $domdoc->getElementsByTagName("URI");
	$uri = $uri->item(0)->nodeValue;

	return $uri;
}

function getAssociationHandle($url){
	$d = getCurl($url);
	if(200 != $d['header']['http_code']){
		return '';
	}

	$assoc_handle = '';

	$lines = explode("\n", $d['data']);

	foreach($lines as $line){
		if(substr($line, 0, 13) == "assoc_handle:"){
			$assoc_handle = substr($line, 13);
			break;
		}
	}

	return $assoc_handle;
}

function getAuthentication($url, $data=null){
	$d = getCurl($url, $data);
	if(200 == $d['header']['http_code']){
		if(false !== strpos($d['data'], 'is_valid:true')){
			return true;
		}else{
			return false;
		}
	}else{
		return false;
	}
}

function getCurl($url, $data=null, $header=null){
	$c = curl_init($url);
	curl_setopt($c, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($c, CURLOPT_HEADER, false);
	curl_setopt($c, CURLOPT_SSL_VERIFYPEER, false);
	if(!empty($data)){
		curl_setopt($c, CURLOPT_POST, 1);
		curl_setopt($c, CURLOPT_POSTFIELDS, $data);
	}
	if(!empty($header)){
		curl_setopt($c, CURLOPT_HTTPHEADER, $header);
	}
	$d['data'] = curl_exec($c);
	$d['header'] = curl_getinfo($c);
	curl_close($c);
	return $d;
}

function getAuthenticationSigned($d){
	$data["openid.assoc_handle"] = $d['openid_assoc_handle'];
	$data["openid.sig"] = $d['openid_sig'];
	$data["openid.signed"] = $d['openid_signed'];
	//$arr_underscores    = array('ns_', 'pape_', 'sreg_');
	//$arr_periods        = array('ns.', 'pape.', 'sreg.');
	//$arr_signed = explode(",", str_replace($arr_periods, $arr_underscores, $_REQUEST["openid_signed"]));
	$arr_signed = explode(',', $d['openid_signed']);
	for($i=0; $i<count($arr_signed); $i++){
		$s = str_replace('.', '_', $arr_signed[$i]);
		$c = $d['openid_'.$s];
		//if($c != ""){
			$data['openid.'.$arr_signed[$i]] = $c;
		//}
	}
	$data['openid.mode'] = 'check_authentication';
	return $data;
}

function LocationHtml($url, $e=null){
	if(empty($url))
		exit;
	echo('<html>');
	echo('<head>');
	echo('<title>Redirect to: '.$url.'</title>');
	echo('<meta http-equiv="refresh" content="1;url='.$url.'">');
	echo('</head>');
	echo('<body bgcolor="#FFFFFF" onload="window.location.href=\''.$url.'\'">');
	echo('<table border="0" cellpadding="0" cellspacing="0" bgcolor="#FFFFFF" height="100%" width="100%">');
	echo('<tr>');
	echo('<td align="center" valign="middle">');
	echo('<a href="'.$url.'" style="color:#000000;text-decoration:none">');
	echo('<img src="http://freebapp.org/static/images/location.gif" border="0" alt="Redirect to: '.$url.'" title="Redirect to: '.$url.'"/>');
	echo('</a>');
	echo('</td>');
	echo('</tr>');
	echo('</table>');
	if(!empty($e)){
		echo('<script type="text/javascript">');
		if(is_array($e))
			echo('alert("'.implode('\n', $e).'");');
		else
			echo('alert("'.$e.'");');
		echo('</script>');
	}
	echo('</body>');
	echo('</html>');
	exit;
}
?>

10 Comments

  • 如果有注释就好了,我研读了一下才看明白,挺好用:)

  • jonwang

    拿不到yahoo的数据

  • eddytree

    这个代码有人维护不?

  • 王炜大哥,通过你提供的方法以上的功能我都实现了,但是现在我有一个问题,就是登陆后怎样判断用户还未退出,比如用google用户来说,用户通过验证登陆到了我的应用程序中(也登陆到了google),但是此时用户退出google登陆,刷新我应用程序,我怎样判断此用户已经退出google要求他从新登陆

  • 王炜

    这似乎无法判断,openid只是提供用户身份的识别,而不理会openid提供商的状态。这样对“记住用户身份”的网站有安全的漏洞!

  • 您写过facebook接口吗,请问facebook中可以实现获取用户的邮箱吗?

  • 你好王炜
    我出现这个错误
    不知道如何解决了
    https://consent.live.com/pp900/Error.aspx?mkt=zh-CN&ErrorCode=2002

  • costaxu

    貌似您的google/yahoo的associate过程没有成功。$data[‘openid.session_type’] = ‘DH-SHA1’;要设置dh_module dh_gen dh_consumer_public 才可以。

  • yanghaoquan.openid.org.cn

    王炜:
    您好!我是一名在校学生,对openid比较感兴趣。在进行实践过程中,遇到如下的问题,想请教一下您!
    1:在openid2.0协议里边描述:
    1.1:收到一个针对”checkid_immediated”模式请求的否定断言的时候,RP应该使用“check_setup”模式构造一个新的认证请求。
    1.2:针对及时请求的否定断言满足以下形式:
    openid.ns:略
    openid.mode:setup_needed
    我现在的疑惑:
    1:在什么情况下会遇到即时请求的否定断言?
    2:您方便的话,可以给我举一个关于终端用户在登录过程中遇到“即时请求的否定断言”这种情况的实例吗?
    谢谢您!
    我的邮箱:yanghaoquan@126.com

  • People deserve very good life and home loans or financial loan can make it better. Just because people’s freedom depends on money.

Leave a Reply to costaxu Cancel reply