Browse Source

WechatAuth

master
林一峰 7 years ago
parent
commit
0ce3dd54cd
  1. 77
      app/Common/WechatAuth.php
  2. 75
      app/Http/Controllers/Api/UserController.php
  3. 52
      app/Http/Controllers/Weixin/UserController.php
  4. 6
      app/Http/Model/User.php
  5. 4
      resources/org/wxJsSdk/jssdk.php
  6. 89
      resources/org/wxJsSdk/wx_sample.php
  7. 4
      routes/web.php

77
app/Common/WechatAuth.php

@ -4,42 +4,75 @@ namespace App\Common;
/**
* OAuth2.0微信授权登录实现
*
* @author FLi
* @文件名:GetWxUserInfo.php
*/
class WechatAuth
{
//高级功能->开发者模式->获取
private $app_id = 'xxx';
private $app_secret = 'xxxxxxx';
private $app_id;
private $app_secret;
//$registration_id = getenv('registration_id');
public static function send($msg, $param='')
public function __construct($app_id, $app_secret)
{
$client = new JPushMsg(self::APP_KEY, self::APP_SECRET, null);
$this->app_id = $app_id;
$this->app_secret = $app_secret;
}
$push_payload = $client->push();
$push_payload = $push_payload->setPlatform('all');
if(isset($param['mobile'])){$push_payload = $push_payload->addAlias(md5($param['mobile']));}
$push_payload = $push_payload->addAllAudience();
$push_payload = $push_payload->setNotificationAlert($msg);
/**
* 获取微信授权链接
*
* @param string $redirect_uri 回调地址,授权后重定向的回调链接地址,请使用urlEncode对链接进行处理
* @param mixed $state 可以为空,重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节
*/
public function get_authorize_url($redirect_uri = '', $state = '')
{
return "https://open.weixin.qq.com/connect/oauth2/authorize?appid=".$this->app_id."&redirect_uri=".urlencode($redirect_uri)."&response_type=code&scope=snsapi_userinfo&state=".$state."#wechat_redirect";
}
try
/**
* 获取授权token
*
* @param string $code 通过get_authorize_url获取到的code
*/
public function get_access_token($code = '')
{
$push_payload->send();
$token_url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$this->app_id}&secret={$this->app_secret}&code={$code}&grant_type=authorization_code";
$token_data = $this->http($token_url);
return json_decode($token_data, true);
}
catch (JPushMsg\Exceptions\APIConnectionException $e)
/**
* 获取授权后的微信用户信息
*
* @param string $access_token
* @param string $open_id
*/
public function get_user_info($access_token = '', $open_id = '')
{
Log::info($e);
return false;
$info_url = "https://api.weixin.qq.com/sns/userinfo?access_token={$access_token}&openid={$open_id}&lang=zh_CN";
$info_data = $this->http($info_url);
return json_decode($info_data, true);
}
catch (JPushMsg\Exceptions\APIRequestException $e)
// cURL函数简单封装
function http($url, $data = null)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
if (!empty($data))
{
Log::info($e);
return false;
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
return true;
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
}

75
app/Http/Controllers/Api/UserController.php

@ -127,12 +127,35 @@ class UserController extends CommonController
return ReturnData::create(ReturnData::SUCCESS);
}
//登录
public function wxLogin(Request $request)
{
$data['user_name'] = $request->input('user_name','');
$data['password'] = $request->input('password','');
$data['openid'] = $request->input('openid','');
if (($data['user_name']=='' && $data['password']=='') || $data['openid']=='')
{
return ReturnData::create(ReturnData::PARAMS_ERROR);
}
$res = User::wxLogin($data);
if ($res === false)
{
return ReturnData::create(ReturnData::PARAMS_ERROR,null,'账号或密码错误');
}
return ReturnData::create(ReturnData::SUCCESS,$res);
}
//注册
public function wxRegister(Request $request)
{
$data['mobile'] = $request->input('mobile','');
$data['user_name'] = $request->input('user_name','');
$data['password'] = $request->input('password','');
$data['parent_id'] = $request->input('parent_id','');
$parent_mobile = $request->input('parent_mobile','');
if (($data['mobile']=='' && $data['user_name']=='') || $data['password']=='')
@ -179,25 +202,59 @@ class UserController extends CommonController
return ReturnData::create(ReturnData::SUCCESS,$res);
}
//登录
public function wxLogin(Request $request)
//微信授权注册
public function wxOauthRegister(Request $request)
{
$data['user_name'] = $request->input('user_name','');
$data['password'] = $request->input('password','');
$data['openid'] = $data['user_name'] = $request->input('openid','');
$data['sex'] = $request->input('sex','');
$data['head_img'] = $request->input('head_img','');
$data['nickname'] = $request->input('nickname','');
$data['parent_id'] = $request->input('parent_id','');
$parent_mobile = $request->input('parent_mobile','');
$data['mobile'] = $request->input('mobile','');
if ($data['user_name']=='' || $data['password']=='')
if ($data['openid']=='')
{
return ReturnData::create(ReturnData::PARAMS_ERROR);
}
$res = User::wxLogin($data);
if ($parent_mobile!='')
{
if($user = User::getOneUser(array('mobile'=>$parent_mobile)))
{
$data['parent_id'] = $user->id;
}
else
{
return ReturnData::create(ReturnData::PARAMS_ERROR,null,'推荐人手机号错误');
}
}
if ($res === false)
if (isset($data['mobile']) && !Helper::isValidMobile($data['mobile']))
{
return ReturnData::create(ReturnData::PARAMS_ERROR,null,'账号或密码错误');
return ReturnData::create(ReturnData::MOBILE_FORMAT_FAIL);
}
return ReturnData::create(ReturnData::SUCCESS,$res);
//判断是否已经注册
if (User::getOneUser(array('mobile'=>$data['mobile'])))
{
return ReturnData::create(ReturnData::MOBILE_EXIST);
}
if (User::getOneUser(array('openid'=>$data['openid'])))
{
return ReturnData::create(ReturnData::SUCCESS,User::wxLogin(array('openid'=>$data['openid'])));
}
//添加用户
$res = User::wxRegister($data);
if($res === false)
{
return ReturnData::create(ReturnData::SYSTEM_FAIL);
}
return ReturnData::create(ReturnData::SUCCESS,User::wxLogin(array('openid'=>$data['openid'])));
}
//验证码登录

52
app/Http/Controllers/Weixin/UserController.php

@ -4,6 +4,7 @@ namespace App\Http\Controllers\Weixin;
use App\Http\Controllers\Weixin\CommonController;
use Illuminate\Http\Request;
use App\Common\ReturnCode;
use App\Common\WechatAuth;
class UserController extends CommonController
{
@ -274,41 +275,60 @@ class UserController extends CommonController
//微信网页授权登录
public function oauth(Request $request)
{
if(isset($_SESSION['weixin_user_info']))
$wechat_auth = new WechatAuth(sysconfig('CMS_WX_APPID'),sysconfig('CMS_WX_APPSECRET'));
// 获取code码,用于和微信服务器申请token。 注:依据OAuth2.0要求,此处授权登录需要用户端操作
if(!isset($_GET['code']))
{
if(isset($_SERVER["HTTP_REFERER"])){header('Location: '.$_SERVER["HTTP_REFERER"]);exit;}
header('Location: '.route('weixin_user'));exit;
$http_type = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? 'https://' : 'http://';
$callback_url = $http_type . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; //回调地址,当前页面
//-------生成唯一随机串防CSRF攻击
$state = md5(uniqid(rand(), true));
$_SESSION['weixin_oauth']['state'] = $state; //存到SESSION
$authorize_url = $wechat_auth->get_authorize_url($callback_url, $state);
header("Location: $authorize_url");exit;
}
if($_SERVER['REQUEST_METHOD'] == 'POST')
// 依据code码去获取openid和access_token,自己的后台服务器直接向微信服务器申请即可
if (isset($_GET['code']))
{
if($_POST['user_name'] == '')
$_SESSION['weixin_oauth']['code'] = $_GET['code'];
if($_GET['state'] != $_SESSION['weixin_oauth']['state'])
{
$this->error_jump('账号不能为空');
exit("您访问的页面不存在或已被删除!");
}
if($_POST['password'] == '')
//得到 access_token 与 openid
$_SESSION['weixin_oauth']['token'] = $wechat_auth->get_access_token($_GET['code']);
}
// 依据申请到的access_token和openid,申请Userinfo信息。
if (isset($_SESSION['weixin_oauth']['token']))
{
$this->error_jump('密码不能为空');
$_SESSION['weixin_oauth']['userinfo'] = $wechat_auth->get_user_info($_SESSION['weixin_oauth']['token']['access_token'], $_SESSION['weixin_oauth']['token']['openid']);
}
$postdata = array(
'user_name' => $_POST['user_name'],
'password' => md5($_POST['password'])
'openid' => $_SESSION['weixin_oauth']['token']['openid'],
'nickname' => $_SESSION['weixin_oauth']['userinfo']['nickname'],
'sex' => $_SESSION['weixin_oauth']['userinfo']['sex'],
'head_img' => $_SESSION['weixin_oauth']['userinfo']['headimgurl'],
'parent_id' => '',
'parent_mobile' => '',
'mobile' => ''
);
$url = env('APP_API_URL')."/wx_login";
$url = env('APP_API_URL')."/wx_oauth_register";
$res = curl_request($url,$postdata,'POST');
if($res['code'] != ReturnCode::SUCCESS_CODE){$this->error_jump('登录失败');}
dd($postdata);
if($res['code'] != ReturnCode::SUCCESS_CODE){$this->error_jump('系统错误');}
$_SESSION['weixin_user_info'] = $res['data'];
header('Location: '.route('weixin_user'));exit;
}
return view('weixin.user.login');
}
//登录
public function login(Request $request)
{

6
app/Http/Model/User.php

@ -180,6 +180,10 @@ class User extends BaseModel
if(isset($mobile)){$data['mobile'] = $mobile;}
if(isset($password)){$data['password'] = $password;} //md5加密
if(isset($parent_id)){$data['parent_id'] = $parent_id;}
if(isset($openid)){$data['openid'] = $openid}
if(isset($sex)){$data['sex'] = $sex}
if(isset($head_img)){$data['head_img'] = $head_img}
if(isset($nickname)){$data['nickname'] = $nickname}
if (isset($data) && $id = self::add($data))
{
@ -195,7 +199,7 @@ class User extends BaseModel
{
extract($param); //参数
$user = self::where(array('mobile'=>$user_name,'password'=>$password))->orWhere(array('user_name'=>$user_name,'password'=>$password))->first();
$user = self::where(array('mobile'=>$user_name,'password'=>$password))->orWhere(array('user_name'=>$user_name,'password'=>$password))->orWhere(array('openid'=>$openid))->first();
if(!$user){return false;}

4
resources/org/wxJsSdk/jssdk.php

@ -110,8 +110,8 @@ class JSSDK
curl_setopt($curl, CURLOPT_TIMEOUT, 500);
// 为保证第三方服务器与微信服务器之间数据传输的安全性,所有微信接口采用https方式调用,必须使用下面2行代码打开ssl安全校验。
// 如果在部署过程中代码在此处验证失败,请到 http://curl.haxx.se/ca/cacert.pem 下载新的证书判别文件。
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_URL, $url);
$res = curl_exec($curl);

89
resources/org/wxJsSdk/wx_sample.php

@ -0,0 +1,89 @@
<?php
/**
* wechat php test
*/
//define your token
define("TOKEN", "weixin");
$wechatObj = new wechatCallbackapiTest();//将11行的class类实例化
$wechatObj->valid();//使用-》访问类中valid方法,用来验证开发模式
//11--23行代码为签名及接口验证。
class wechatCallbackapiTest
{
public function valid()//验证接口的方法
{
$echoStr = $_GET["echostr"];//从微信用户端获取一个随机字符赋予变量echostr
//valid signature , option访问地61行的checkSignature签名验证方法,如果签名一致,输出变量echostr,完整验证配置接口的操作
if($this->checkSignature()){
echo $echoStr;
exit;
}
}
//公有的responseMsg的方法,是我们回复微信的关键。以后的章节修改代码就是修改这个。
public function responseMsg()
{
//get post data, May be due to the different environments
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];//将用户端放松的数据保存到变量postStr中,由于微信端发送的都是xml,使用postStr无法解析,故使用$GLOBALS["HTTP_RAW_POST_DATA"]获取
//extract post data如果用户端数据不为空,执行30-55否则56-58
if (!empty($postStr)){
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);//将postStr变量进行解析并赋予变量postObj。simplexml_load_string()函数是php中一个解析XML的函数,SimpleXMLElement为新对象的类,LIBXML_NOCDATA表示将CDATA设置为文本节点,CDATA标签中的文本XML不进行解析
$fromUsername = $postObj->FromUserName;//将微信用户端的用户名赋予变量FromUserName
$toUsername = $postObj->ToUserName;//将你的微信公众账号ID赋予变量ToUserName
$keyword = trim($postObj->Content);//将用户微信发来的文本内容去掉空格后赋予变量keyword
$time = time();//将系统时间赋予变量time
//构建XML格式的文本赋予变量textTpl,注意XML格式为微信内容固定格式,详见文档
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
<FuncFlag>0</FuncFlag>
</xml>";
//39行,%s表示要转换成字符的数据类型,CDATA表示不转义
//40行为微信来源方
//41行为系统时间
//42行为回复微信的信息类型
//43行为回复微信的内容
//44行为是否星标微信
//XML格式文本结束符号
if(!empty( $keyword ))//如果用户端微信发来的文本内容不为空,执行46--51否则52--53
{
$msgType = "text";//回复文本信息类型为text型,变量类型为msgType
$contentStr = "Welcome to wechat world!";//我们进行文本输入的内容,变量名为contentStr,如果你要更改回复信息,就在这儿
$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);//将XML格式中的变量分别赋值。注意sprintf函数
echo $resultStr;//输出回复信息,即发送微信
}else{
echo "Input something...";//不发送到微信端,只是测试使用
}
}else {
echo "";//回复为空,无意义,调试用
exit;
}
}
//签名验证程序 ,checkSignature被18行调用。官方加密、校验流程:将token,timestamp,nonce这三个参数进行字典序排序,然后将这三个参数字符串拼接成一个字符串惊喜shal加密,开发者获得加密后的字符串可以与signature对比,表示该请求来源于微信。
private function checkSignature()
{
$signature = $_GET["signature"];//从用户端获取签名赋予变量signature
$timestamp = $_GET["timestamp"];//从用户端获取时间戳赋予变量timestamp
$nonce = $_GET["nonce"]; //从用户端获取随机数赋予变量nonce
$token = TOKEN;//将常量token赋予变量token
$tmpArr = array($token, $timestamp, $nonce);//简历数组变量tmpArr
sort($tmpArr, SORT_STRING);//新建排序
$tmpStr = implode( $tmpArr );//字典排序
$tmpStr = sha1( $tmpStr );//shal加密
//tmpStr与signature值相同,返回真,否则返回假
if( $tmpStr == $signature ){
return true;
}else{
return false;
}
}
}
?>

4
routes/web.php

@ -52,7 +52,7 @@ Route::group(['namespace' => 'Home'], function () {
});
//微信路由
//微信路由,无需登录
Route::group(['prefix' => 'weixin', 'namespace' => 'Weixin'], function () {
Route::get('/', 'IndexController@index')->name('weixin');
Route::get('/page404', 'IndexController@page404')->name('weixin_page404'); //404页面
@ -64,6 +64,7 @@ Route::group(['prefix' => 'weixin', 'namespace' => 'Weixin'], function () {
Route::get('/goods/{id}', 'GoodsController@goodsDetail')->name('weixin_goods_detail'); //商品详情页
Route::get('/goodslist', 'GoodsController@goodsList')->name('weixin_goods_list'); //产品分类页
Route::any('/wxoauth', 'UserController@oauth')->name('weixin_wxoauth'); //微信网页授权
Route::any('/login', 'UserController@login')->name('weixin_login');
Route::any('/register', 'UserController@register')->name('weixin_register');
Route::get('/logout', 'UserController@logout')->name('weixin_user_logout'); //退出
@ -130,6 +131,7 @@ Route::group(['prefix' => 'dataapi', 'namespace' => 'Api', 'middleware' => ['web
//用户
Route::post('/wx_register', 'UserController@wxRegister'); //注册
Route::post('/wx_login', 'UserController@wxLogin'); //登录
Route::post('/wx_oauth_register', 'UserController@wxOauthRegister'); //微信授权注册登录
});
//API接口路由,需token验证

Loading…
Cancel
Save