微信公众号获取用户信息地址: 网页授权
jssdk下载: 获取access_token bmwj
复制这段内容后打开百度网盘手机App,操作更方便哦
域名必须是公网的
将下载好的验证文件, 放到能访问的路径, 例如: thinkphp6框架, 我们只需将 验证文件 放到 public下
在基本配置中, 获取 appid 和 AppSecret
// 测试使用另一个种思路做 微信公众号登陆, 正式服务器上也在使用
public function login(){
//判断用户是否在微信里面打开
$appid = '这个东西填写自己的';
$secret = '这个东西填写自己的';
// 判断是否存在 code
if (isset($_GET['code'])) {
$code = $_GET['code'];
// 获取access_token
$url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=$appid&secret=$secret&code=$code&grant_type=authorization_code";
// curl请求, 我放在下面的封装方法
$result = Curl::get($url);
// 不加true 转为对象, 加上true 转为数组
$decode = json_decode($result, true);
// 如果用户openid 不存在数据库中
if (!(new Personal())->where(['new_openid' => $decode['openid']])->find()){
if (isset($decode['openid'])) {
// 跳转另一个方法进行存入session 和 入库
$url = $this->getUserCreateData($decode);
header("Location: $url");exit;
} else {
// 可以跳转一个 404页面
header("HTTP/1.1 404 Not Found");exit;
}
} else {
// 存在也需要去更新用户头像和 session 的时间
// 获取用户信息和添加入库
$url = $this->getUserCreateData($decode);
header("Location: $url");exit;
}
} else {
// 不存在code 去微信获取code 回调地址填写当前方法, 反正是比较安全的做法, 不需要给前端传任何参数
// 我说下这儿的逻辑, 放到当自己的当前方法微信已经在地址上面拼接了code.
$redirect_uri = urlencode('https://test.com/api/personal/login');
$response_type = 'code';
$scope = 'snsapi_userinfo';
$url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=$appid&redirect_uri=$redirect_uri&response_type=$response_type&scope=$scope&state=STATE#wechat_redirect";
// 跳转微信地址获取code
header("Location: $url");exit;
}
}
添加到数据库中
/**
* 获取用户信息和添加入库
* @param $decode
* @return string|void
* @throws ApiServiceException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
protected function getUserCreateData($decode)
{
$userInfo = $this->getConfigUserInfo($decode['access_token'], $decode['openid']);
// 如果获取成功, 添加入库
if (array_key_exists('openid',$userInfo) && array_key_exists('nickname',$userInfo)) {
// 添加方法也在下方
$data = (new Personal())->createUserInfo($userInfo);
// 开启session 会话才能使用 使用可能我是用的框架问题;
session_start();
$_SESSION['name'] = $data['new_token'];
// 跳转微信地址获取code
return "https://test.com/water/";
//
} else {
// 可以跳转一个 404页面
header("HTTP/1.1 404 Not Found");exit;
}
}
/**
* 添加用户信息
* @param array $data
* @return array
* @throws ApiServiceException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function createUserInfo(array $data) : array
{
// 生成token
$token = sha1(md5(uniqid(md5(microtime(true)), true)));
$param['new_openid'] = $data['openid'];
$param['nickname'] = $data['nickname'];
$param['new_sex'] = $data['sex'];
$param['avatar'] = $data['headimgurl'];
$param['new_token'] = $token;
// 查询用户是否注册
$userInfoFind = Db::name('user')->field('id, new_openid, new_sex, mobile, avatar, status, delete_time')
->where([
'new_openid' => $data['openid']
])
->find();
if ($userInfoFind) {
// 修改用户的头像和昵称
$param['update_time'] = time();
self::where(['new_openid' => $data['openid']])->update($param);
// 判断用户头像地址是否含有http https
if (!preg_match('/(http|https):\/\/([\w.]+\/?)\S*/', $userInfoFind['avatar'])) {
$userInfoFind['domain'] = request()->domain();
}
$userInfoFind['new_token'] = $param['new_token'];
// 缓存时间 180天
if (!Cache::set($param['new_token'], $userInfoFind, 1296000)) throw new ApiServiceException('登陆失败');
return $userInfoFind->toArray();
} else {
//用户第一次注册进来
$param['update_time'] = $param['create_time'] = time();
$save = Db::('user')->insertGetId($param);
if ($save) {
$param['id'] = $save;
$param['mobile'] = '';
$param['status'] = 1;
$param['delete_time'] = 0;
// 缓存时间 180天
if (!Cache::set($param['new_token'], $param, 1296000)) throw new ApiServiceException('添加失败');
return $param;
} else {
throw new ApiServiceException('添加失败');
}
}
}
/**
* 获取用户基本信息
* @param $access_token
* @param $openid
* @return mixed
*/
protected function getConfigUserInfo($access_token, $openid)
{
$url = "https://api.weixin.qq.com/sns/userinfo?access_token=$access_token&openid=$openid&lang=zh_CN";
$result = Curl::get($url);
// 不加true 转为对象, 加上true 转为数组
return json_decode($result, true);
}
/**
* 该函数理由三个执行方法
* 1 先用code 获取access_token
* 2 在用 access_token 换取 refresh_token 有效时间为30天
* 3 使用access_token和openid 获取用户的基本信息
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getAccessToken() :Json
{
session_start();
// 获取session
$token = $_SESSION['name'];
// 获取用户信息
$data = Cache::get($token);
// 不为数组转为数组返回
( !is_array($data) ) && ( $data = $data->toArray() );
if ($data) {
return api_success($data);
} else {
return api_error('请从新登陆', ['url' => "https://test.com/api/personal/login"], 500, 2);
}
}
这是封装的 curl
class Curl
{
/**
* @param string $url 请求地址
* @param array $params 请求参数
* @param array $header 请求头
* @param int $timeOut 请求时间
* @return bool|string
*/
public static function delete(string $url, array $params = [], array $header = [], int $timeOut = 10)
{
return self::curlRequest($url, 'DELETE', $params, '', $header, $timeOut);
}
/**
* @param string $url 请求地址
* @param array $header 请求头
* @param int $timeOut 请求时间
* @return bool|string
*/
public static function get(string $url, array $header = [], int $timeOut = 10)
{
return self::curlRequest($url, 'GET', [], '', $header, $timeOut);
}
/**
* @param string $url 请求地址
* @param array $params 请求参数
* @param string $paramsType 请求数据类型
* @param array $header 请求头
* @param int $timeOut 请求时间
* @return bool|string
*/
public static function post(string $url, array $params = [], string $paramsType = '', array $header = [], int $timeOut = 10)
{
return self::curlRequest($url, 'POST', $params, $paramsType, $header, $timeOut);
}
/**
* @param string $url 请求地址
* @param string $method 请求方式
* @param array $params 请求参数
* @param string $paramsType 请求数据类型
* @param array $header 请求头
* @param int $timeOut 请求时间
* @return bool|string
*/
private static function curlRequest(string $url, string $method = '', array $params = [], string $paramsType = '', array $header = [], int $timeOut)
{
$resHeader = [];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url); // 地址
curl_setopt($ch, CURLOPT_HEADER, 0); // 请求头
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //获取的信息以文件流的形式放回, 而不是直接输出
curl_setopt($ch, CURLINFO_HEADER_OUT, true); // TRUE 时追踪句柄的请求字符串, 这个很关键,就是允许你查看请求header
curl_setopt($ch, CURLOPT_TIMEOUT, $timeOut); // 告诉成功 PHP 从服务器接收缓冲完成前需要等待多长时间,如果目标是个巨大的文件,生成内容速度过慢或者链路速度过慢,这个参数就会很有用
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeOut); // 告诉 PHP 在成功连接服务器前等待多久(连接成功之后就会开始缓冲输出),这个参数是为了应对目标服务器的过载,下线,或者崩溃等可能状况
curl_setopt($ch, CURLOPT_FAILONERROR, false); // PHP在发生错误(HTTP代码返回大于等于300)时,不显示,设置这个选项为一人非零值。默认行为是返回一个正常页,忽略代码。
if (1 == strpos('$'.$url, "https://")) {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
}
if ($method == 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
if ($paramsType == 'JSON') {
$resHeader[] = 'Content-Type: application/x-www-form-urlencoded;charset=UTF-8';
$resParams = json_encode($params);
} else {
$resParams = http_build_query($params);
}
curl_setopt($ch, CURLOPT_POSTFIELDS, $resParams);
} else if ($method == 'PUT') {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
} else if ($method == 'DELETE') {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
}
$resHeader = array_merge($resHeader, $header);
if ($resHeader) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $resHeader);
}
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
}
使用的uniapp做的将下面代码放到 App.vue文件中
``
onLaunch: function() {
this.getToken({}).then((res) => {
console.log(res);
if (res.data.code == 200) {
// 头像
let headImg = res.data.data.avatar
// 绑定户号状态
let accountType = res.data.data.default_type
// token
let Token = res.data.data.new_token
uni.setStorage({
key: 'userinfo',
data: {
headImg: headImg,
accountType: accountType,
Token: Token,
},
success: function() {
console.log('success');
}
});
uni.getStorage({
key: 'userinfo',
success: function(res) {
console.log(res.data);
}
});
} else {
window.location.href = res.data.data.url
}
})
},
methods: {
// 访问后端方法即可
getToken() {
uni.request({
// 携带 cookie
xhrFields: {
withCredentials: true
},
url: 'https://test.com/api/personal/getAccessToken',
methods: 'POST',
success: (res) => {
return res
}
})
},
}
我们使用的是 thinkphp 在public 下建一个 test 文件夹, 将打包好的 static和index.html 放在当中. 访问项目直接 https://test.com/api/personal/login, 就能访问成功