ドキュメント:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319

WeChatの認証ログインは、QQやSinaなどのプラットフォームの認証ログインとほぼ同じで、いずれもOAuth2.0認証方式を採用しています。
WeChatの認証は2種類に分かれています:

  1. サイレント認証
  2. ポップアップ認証、ユーザーの手動同意が必要

2種類のscopeの違いについて

  1. snsapi_baseをscopeとして開始されるウェブ認証は、ページにアクセスしたユーザーのopenidを取得するためのもので、サイレント認証であり、自動的にコールバックページにリダイレクトされます。ユーザーは直接コールバックページ(通常は業務ページ)にアクセスしたように感じます。
  2. snsapi_userinfoをscopeとして開始されるウェブ認証は、ユーザーの基本情報を取得するためのものです。この認証はユーザーの手動同意が必要ですが、一度同意すれば、公式アカウントをフォローしていなくても、認証後にそのユーザーの基本情報を取得できます。

ユーザー管理関連のAPIにおける「ユーザー基本情報取得API」は、ユーザーが公式アカウントとメッセージのやり取りをするか、フォローした後のイベントプッシュがあって初めて、ユーザーのOpenIDに基づいて基本情報を取得できます。このAPIを含む他のWeChat APIは、すべて対象ユーザー(openid)が公式アカウントをフォローしている場合にのみ、正常に呼び出すことができます。

具体的には、ウェブ認証のフローは4つのステップに分かれています:

  1. ユーザーを認証ページに誘導し、同意を得てcodeを取得する
  2. codeを使用してウェブ認証用のaccess_tokenを取得する(基本サポートのaccess_tokenとは異なる)
  3. 必要に応じて、開発者はウェブ認証用のaccess_tokenを更新し、期限切れを回避する
  4. ウェブ認証用のaccess_tokenとopenidを使用してユーザーの基本情報を取得する(UnionIDメカニズムをサポート)

以下はカプセル化されたWeChat操作クラスです。access_tokenとticketを保存するために2つのデータテーブルを使用します。これらには有効期限があり、1日あたりのリクエスト数に上限があるため、開発者は自身で保存する必要があります。

PHP
<?php
/**
*   WeChat操作テーブル
*   wxtoken テーブル構造
*   id
*   access_token
*   addtime
*   wxticket テーブル構造
*   id
*   ticket
*   addtime
*/
class WX {
	private $appid;
	private $appserect;
	private $curl;
	private $msg;
	protected $errs = array(
		'-1' => 'システムがビジーです。開発者はしばらくしてから再試行してください',
		'0' => 'リクエスト成功',
		'40001' => 'AppSecretが間違っているか、この公式アカウントのものではありません。開発者はAppSecretが正しいことを確認してください',
		'40002' => 'grant_typeフィールドの値がclient_credentialであることを確認してください',
		'40164' => 'APIを呼び出したIPアドレスがホワイトリストにありません。APIのIPホワイトリストで設定してください。',
	);
	function __construct($appid, $appserect) {
		$this->appid = $appid;
		$this->appserect = $appserect;
		$this->curl = new Curl();
	}
	/*
	WeChatウェブ認証ログイン 公式アカウント設定 - 機能設定 - ウェブ認証ドメインでの設定が必要
	第一歩:ユーザーが認証に同意し、codeを取得
	scope : snsapi_base openidのみ取得可能、直接リダイレクト
	snsapi_userinfo
	*/
	public function getCode($redirect_uri, $scope = 'snsapi_userinfo',$state = '1') {
		$url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->appid}&redirect_uri={$redirect_uri}&response_type=code&scope={$scope}&state={$state}#wechat_redirect";
		header("Location:{$url}");
		exit;
	}
	/*
	第二歩:codeを使用してウェブ認証用のaccess_tokenを取得
	*/
	public function getAccessTokenByCode($code) {
		$url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$this->appid}&secret={$this->appserect}&code={$code}&grant_type=authorization_code";
		// exit($url);
		// $curl = new Curl();
		$result = $this->curl->doGet($url);
		if (!$result) {
			// $this->curl->getError()
			$this->msg = "トークンの取得に失敗しました";
			return false;
		}
		$result = json_decode($result, true);
		if ($result['errcode']) {
			$this->msg = $result['errmsg'];
			return false;
		}
		return $result;
	}
	// 第三歩:access_tokenを更新(必要な場合) code経由でopenidを取得 $type 0サイレント認証 1ポップアップ認証
	public function getUserInfo($code, $type = 0, $lang = 'zh_CN ') {
		$result = $this->getAccessTokenByCode($code);
			if (!$result) {
			return false;
		}
		$member = C::t(PT_USER)->getByOpenid($result['openid']);
	if ($member) {
		return $member;
	} else {
		if ($type) {
			$url = "https://api.weixin.qq.com/sns/userinfo?access_token={$result['access_token']}&openid={$result['openid']}&lang={$lang}";
			// $return = $this->curl->doGet($url);
			// このAPIは挙動がおかしく、強制的にファイルヘッダーを表示します
			$return = file_get_contents($url);
			if (!$return) {
				$this->msg = 'ユーザー情報の取得に失敗しました';
				return false;
			}
			$return = json_decode($return, true);
			if (!$return) {
				$this->msg = 'ユーザー情報の取得リターンに失敗しました';
				return false;
			}
			// file_put_contents('ccc.txt',print_r($return,true),FILE_APPEND);
			$data = array(
				'openid' => $return['openid'],
				'name' => $return['nickname'],
				'sex' => $return['sex'],
				'province' => $return['province'],
				'city' => $return['city'],
				'country' => $return['country'],
				'img' => $return['headimgurl'],
				'bindtel' => 0,
			);
		} else {
			$data = array(
				'openid' => $result['openid'],
				'username' => "WeChatユーザー_" . random(6,1)
			);
		}
		$name = rand(100000, 1000000000);
		$e = $name . "@qq.com";
		$password = $e;
		$id = UserAddEdit(0, $data['username'], $password, $e,10,0,"", $msg);
		if ($id <= 0) {
			$this->msg = $msg;
			return false;
		}
		C::t(PT_USER)->update($data, $id);
		$member = C::t(PT_USER)->get($id);
		return $member;
		}
	}
	/*
	公式アカウント セキュリティセンターでIPホワイトリストを設定
	公式アカウントのグローバルでユニークなAPI呼び出し資格情報。公式アカウントが各APIを呼び出す際にはaccess_tokenを使用する必要があります。開発者は適切に保存する必要があります。access_tokenの保存には少なくとも512文字のスペースを確保してください。access_tokenの有効期間は現在2時間で、定期的に更新する必要があります。重複して取得すると、前回取得したaccess_tokenが無効になります。
	*/
	public function getAccessToken($type) {
		$addtime = TIMESTAMP - 7200;
		$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->appid}&secret={$this->appserect}";
		$row = C::t(PT_WXTOKEN)->getNew($addtime, $type);
		if ($row) {
			return $row['access_token'];
		} else {
			$result = $this->curl->doGet($url);
			if (!$result) {
				$this->msg = "トークンコンテンツを取得できません";
				return false;
			}
			$result = json_decode($result, true);
			if (!$result) {
				$this->msg = "トークンコンテンツの解析に失敗しました";
				return false;
			}
			if ($result['access_token']) {
				C::t(PT_WXTOKEN)->addToken($result['access_token'], $type);
				return $result['access_token'];
			} else {
				$this->msg = "トークンの取得に失敗しました";
				return false;
			}
		}
	}
	// JSチケットを取得 公式アカウント設定 - 機能設定 - JSインターフェースセキュアドメインでの設定が必要
	public function getJsTicket() {
		$addtime = TIMESTAMP - 7200;
		$row = C::t(PT_WXTICKET)->getNew($addtime);
		if ($row) {
			return $row['ticket'];
		} else {
			$token = $this->getAccessToken();
			if (!$token) {
				return false;
			}
			$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={$token}&type=jsapi";
			$result = $this->curl->doGet($url);
			if (!$result) {
				$this->msg = "JSチケットを取得できません";
				return false;
			}
			$result = json_decode($result, true);
			if (!$result) {
				$this->msg = "JSチケットコンテンツの解析に失敗しました";
				return false;
			}
			if ($result['ticket']) {
				C::t(PT_WXTICKET)->addTicket($result['ticket']);
				return $result['ticket'];
			} else {
				$this->msg = "JSチケットの取得に失敗しました";
				return false;
			}
		}
	}
	// js sdk チケット署名 現在のウェブページのURL、#およびそれ以降の部分は含まない
	public function jsSign($data) {
		// 1.署名対象のすべてのパラメータをフィールド名のASCIIコード順(辞書順)でソートする
		ksort($data);
		// 2.URLキー・バリューペアの形式(つまりkey1=value1&key2=value2…)で文字列string1に連結する。元の値を使用し、URLエンコードは行わない
		$string1 = $this->ToUrlParams($data);
		// echo "string1:{$string1}<br/>";
		// 3.string1をsha1で暗号化する
		$sign = sha1($string1);
		// echo "signature:{$sign}<br/>";
		return $sign;
	}
	// メッセージ内容を取得
	public function getMsg() {
		return $this->msg;
	}
	/**
	* パラメータをURLパラメータ形式にフォーマットする
	*/
	public function ToUrlParams($data) {
		$buff = "";
		foreach ($data as $k => $v) {
			if ($k != "sign" && $v != "" && !is_array($v)) {
				$buff .= $k . "=" . $v . "&";
			}
		}
		$buff = trim($buff, "&");
		return $buff;
	}
}
?>
クリックして展開し、詳細を表示
PHP
// WeChatログイン
function wxlogin() {
	global $_G,$identifier,$config,$wx;
	if (!$_G['uid']) {
		if ($_GET['state']) {
			//コールバック
			$member = $wx->getUserInfo($_GET['code']);
			if (!$member) {
				exit($wx->getMsg());
			}
			if (!function_exists("setloginstatus")) {
				include_once libfile('function/member');
			}
			// ログイン状態を設定$wx
			setloginstatus($member, 2592000);
			checkfollowfeed();
			$_G['uid'] = $member['uid'];
			$_G['member'] = $member;
		} else {
			//認証をリクエスト パラメータをエンコード
			$redirect = urlencode(getProtocol() . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
			$wx->getCode($redirect, 'snsapi_base');
		}
	}
}
function getProtocol() {
	return is_HTTPS() ? 'https://' : 'http://';
}
function is_HTTPS() {  if ($_SERVER['HTTPS'] === 1 || $_SERVER['HTTPS'] === 'on' || $_SERVER['SERVER_PORT'] == 443) {
		return true;
	}
	return false;
}
クリックして展開し、詳細を表示

著作権表示

著者: MoeJue

リンク: https://ja.moejue.cn/posts/88/

ライセンス: クリエイティブ・コモンズ表示-非営利-継承4.0国際ライセンス

この作品は、クリエイティブ・コモンズ表示-非営利-継承4.0国際ライセンスに基づいてライセンスされています。

検索を開始

キーワードを入力して記事を検索

↑↓
ESC
⌘K ショートカット