ヒント:このメッセージが表示されている場合、現在の記事は元のemlogブログシステムからこちらに移行されたものであり、記事の公開日時がかなり前であるため、編成や内容が完全でない可能性があります。ご了承ください。
WeChat 認証ログイン
日付:2019-4-5 阿珏 コードをいじる 閲覧:1874 回 コメント:1 件
ドキュメント: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319WeChatの認証ログインは、QQや新浪などのプラットフォームの認証ログインと大差なく、すべて Oauth OAuth2.0認証方式を採用しています。
WeChatの認証は2種類に分かれます:
- サイレント認証
- ポップアップ認証、ユーザーの手動同意が必要
2種類のscopeの違いの説明
具体的には、ウェブ認証プロセスは4つのステップに分かれます:
- snsapi_ baseをscopeとして発起されたウェブ認証は、ページに入るユーザーのopenidを取得するためのもので、サイレント認証で自動的にコールバックページにリダイレクトされます。ユーザーが認識するのは、直接コールバックページ(通常はビジネスページ)に入ったことです。
- snsapi_userinfoをscopeとして発起されたウェブ認証は、ユーザーの基本情報を取得するためのものです。しかし、この認証はユーザーの手動同意が必要であり、ユーザーが同意したため、特に注意する必要はなく、認証後にそのユーザーの基本情報を取得できます。
具体的には、ウェブ認証プロセスは4つのステップに分かれます:
- ユーザーを認証ページに誘導して同意を得て、codeを取得
- codeを使ってウェブ認証access_tokenを取得(基本サポートのaccess_tokenとは異なる)
- 必要に応じて、開発者はウェブ認証access_tokenを更新して、期限切れを防ぐことができます
- ウェブ認証access_tokenとopenidを使用してユーザーの基本情報を取得(UnionIDメカニズムをサポート)
以下は、access_token と ticket を保存するために 2 つのデータテーブルを使用する WeChat 操作クラスです。これらは有効期限があり、1 日のリクエスト数に上限があるため、開発者は自分で保存する必要があります。
<?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がこの公式アカウントに属していません。開発者はAppSecretの正確性を確認してください。',
'40002' => 'grant_typeフィールドの値がclient_credentialであることを確認してください。',
'40164' => '呼び出しインターフェースのIPアドレスがホワイトリストにありません。インターフェース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);
// このインターフェースは問題があり、強制的にファイルヘッダーを表示します
$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ホワイトリスト設定
公式アカウントのグローバルユニークインターフェース呼び出し資格情報で、公式アカウントが各インターフェースを呼び出す際に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;
}
}
?>
// 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;
}
ユーザーコメント:
トップニュース 2 年前 (2019-04-11)
記事は素晴らしいので、応援します。