企业微信网页授权

1.判断是否登录,如果登录了,就让其直接访问.没有登录跳转到登录授权的方法

在laravel中代码实现
a.让需要登录的所有路由使用中间件包裹

//授权登陆
Route::get('auth/login', 'Front\AuthController@getLogin')->name('login');
//需要登录才可以访问的网页
Route::group([ 'middleware' => 'auth', 'namespace' => 'Front'], function(){
     .......
});
//其他不需要登录可以访问的网页
......

b.中间件判断登录代码

public function handle($request, Closure $next)
    {
        if (!\Auth::check()){//判断登录
            //没有登录
            if ($request->ajax()) {//如果是异步
                return response('Unauthorized.', 401);
            } else {
                return redirect('auth/login');//跳转到授权登录的方法
            }
        }
        //登录继续执行
        return $next($request);
    }
}

2.授权登录的逻辑
a.判断网页来源,是自己跳转还是微信返回的,发送请求 构造链接 目的是为了获取code

$state=$request->state;//初始的时候没有值,点确定按钮后是,submit,获取到code后,get_code
//只有从微信端跳转过来的链接 才可以进入if
if($state!='get_code'){
    //发送获取code请求
    $config = Config::find(1);//从数据库取出来corpid 和 agent_id
    //判断网站是http 还是https 
    if(isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on')
    {
        $redirect_uri = urlencode('https://'.$_SERVER['HTTP_HOST'].'/auth/login');
        //echo "HTTPS";
    }else{
        //echo "HTTP";
        $redirect_uri = urlencode('http://'.$_SERVER['HTTP_HOST'].'/auth/login');
    }
     //snsapi_userinfo  此处使用静默授权
    $url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=$config->corpid&redirect_uri=$redirect_uri&response_type=code&scope=snsapi_userinfo&agentid=$config->agent_id&state=get_code#wechat_redirect";//构造链接
    return redirect($url);//跳转链接
}
//页面将跳转至 redirect_uri?code=CODE&state=STATE
//处理请求结果 
$code = $request->code;
$qywx =new \App\Libs\QyWeixinClass();//此处代码实现会在文章最后给出
$accessToken = $qywx->getAgentAccessToken();
$url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=$accessToken&code=$code";
$res = $qywx->httpGet($url);
$res = json_decode($res);

b.返回结果有两种

  • 当该用户为企业成员时返回
{
  "errcode": 0,
   "errmsg": "ok",
   "UserId":"USERID",
   "DeviceId":"DEVICEID",
   "user_ticket": "USER_TICKET",
   "expires_in":7200
 }
  • 非企业成员授权时返回
{
 "errcode": 0,
 "errmsg": "ok",
 "OpenId":"OPENID",
 "DeviceId":"DEVICEID"
 }

c.根据自己的业务逻辑需求去调整应该怎么处理企业用户和非企业用户

判断请求是否正确返回数据
if (''==$res||$res->errcode != 0){
    //请求没返回正确数据的逻辑
     .....
}
//判断是否是企业用户
if (!isset($res->UserId)){
    //不是企业用户的逻辑
     ......
}

d.保存本用户的登录状态

//只有企业用户才有UserId
$user=User::where("userid",$res->UserId)->first();
Auth::login($user,true);
//跳转到首页
return redirect("/");

附录:

QyWeixinClass这个类的实现:
<?php
namespace App\Libs;
class QyWeixinClass
{
    //属性
    protected $corpid;
    protected $txl_secret;
    protected $agent_id;
    protected $agent_secret;
    protected $check_agent_id;//打卡应用id
    protected $check_agent_secret;//打卡应用密钥
    protected $prePath;//存储的目标路径
    /**
    * 构造器
    */
    public function __construct()
    {
        $config = \App\Models\Config::find(1);
        $this->corpid = $config->corpid;
        $this->txl_secret = $config->txl_secret;
        $this->agent_id = $config->agent_id;
        $this->agent_secret = $config->agent_secret;
        $this->check_agent_id = $config->check_agent_id;
        $this->check_agent_secret = $config->check_agent_secret;
        //存储的目标路径
        $this->prePath = realpath( storage_path( 'wx' ) ) . DIRECTORY_SEPARATOR;
    }
    /**
    * 获取 Access Token, 基础函数
    */
    public function getBaseAccessToken($secret) {
        //TODO: access_token 应该全局存储与更新,以下代码以写入到文件中做示例
        //TODO: 每个应用的access_token应独立存储,此处用secret作为区分应用的标识
        $path = $this->prePath."$secret.php";
        if ( file_exists( $path ) ) {
            $data = json_decode( file_get_contents( $path ) );
        }else {
            $data = new \stdClass();
            $data->expire_time=0;
        }
        if($data->expire_time < time()) {
            $url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={$this->corpid}&corpsecret=$secret";
            $res = json_decode($this->httpGet( $url ));
            $access_token = $res->access_token;
            if($access_token) {
                $data->expire_time = time() + 7000;
                $data->access_token = $access_token;
                $fp = fopen( $path, "w" );
                fwrite( $fp, json_encode( $data ) );
                fclose( $fp );
            }
        } else {
            $access_token = $data->access_token;
        }
        return $access_token;
    }
    /**
    * 获取通讯录的 Access Token
    */
    public function getAccessToken() {
        return $this->getBaseAccessToken($this->txl_secret);
    }
    /**
    * 获取应用的 Access Token
    *
    */
    public function getAgentAccessToken() {
        return $this->getBaseAccessToken($this->agent_secret);
    }
    /**
    * 获取OA打卡应用的 Access Token
    *
    */
    public function getOACheckAccessToken() {
        return $this->getBaseAccessToken($this->check_agent_secret);
    }
    /*
    * 获取 js Ticket
    */
    public function getJsApiTicket() {
        // jsapi_ticket 应该全局存储与更新
        $path = $this->prePath."{$this->agent_id}_jsapi_ticket.php";
        if ( file_exists( $path ) ) {
            $data = json_decode( file_get_contents( $path ) );
        }else {
            $data = new \stdClass();
            $data->expire_time=0;
        }
        if($data->expire_time < time()){
          $app_access_token = $this->getAgentAccessToken();
          $url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=$app_access_token";
          $res = json_decode($this->httpGet( $url ));
          $ticket = $res->ticket;
          if ($ticket) {
                $data->expire_time = time() + 7000;
                $data->jsapi_ticket = $ticket;
                $fp = fopen( $path, "w" );
                fwrite( $fp, json_encode( $data ) );
                fclose( $fp );
          }
        } else {
          $ticket = $data->jsapi_ticket;
        }
        return $ticket;
    }
    /*
    * 获取签名 jssdk
    */
    public function getSignPackage() {
        $jsapiTicket = $this->getJsApiTicket();
        // 注意 URL 一定要动态获取,不能 hardcode.
        $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
        $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
        $timestamp = time();
        $nonceStr = $this->createNonceStr();
        // 这里参数的顺序要按照 key 值 ASCII 码升序排序
        $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";
        $signature = sha1( $string );
        $signPackage = array(
            "appId"    => $this->corpid,
            "nonceStr"  => $nonceStr,
            "timestamp" => $timestamp,
            "url"      => $url,
            "signature" => $signature,
            "rawString" => $string
        );
        return $signPackage;
    }
    /*
    * 发送纯文本消息
    * touser  成员ID列表(消息接收者,多个接收者用‘|’分隔,最多支持1000个)。特殊情况:指定为@all,则向该企业应用的全部成员发送
    * toparty  部门ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    * totag    标签ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    * content  消息内容,最长不超过2048个字节,支持换行(转义过的\n)、A标签
    */
    public function sendTextMsg($content, $touser, $toparty='', $totag='') {
        $accessToken = $this->getAgentAccessToken();
        //消息接口
        $apiurl = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=$accessToken";
        //文本消息
        $arr = [
            "touser"=>$touser,
            "toparty"=>$toparty,
            "totag"=>$totag,
            "msgtype"=>"text",
            "agentid"=>$this->agent_id,
            "text"=>[
                "content"=>$content
            ]
        ];
        $postdata = json_encode( $arr, JSON_UNESCAPED_UNICODE );
        $res = $this->postCurl( $postdata, $apiurl );
        return $res;
    }
    /*
    * 发送文本卡片消息
    * touser  成员ID列表(消息接收者,多个接收者用‘|’分隔,最多支持1000个)。特殊情况:指定为@all,则向关注该企业应用的全部成员发送
    * toparty 部门ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    * totag  标签ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    * title  标题,不超过128个字节,超过会自动截断
    * description    描述,不超过512个字节,支持使用br标签或者空格进行换行,支持div标签,内置了3种文字颜色:灰色(gray)、高亮(highlight)、默认黑色(normal),将其作为div标签的class属性即可;仅限企业微信里有效,企业号无效
    * url    点击后跳转的链接。
    */
    public function sendTextCardMsg( $title, $description, $url, $touser, $toparty='', $totag='' ) {
        $accessToken = $this->getAgentAccessToken();
        //消息接口
        $apiurl = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=$accessToken";
        //文本消息
        $arr = [
            "touser"=>$touser,
            "toparty"=>$toparty,
            "totag"=>$totag,
            "msgtype"=>"textcard",
            "agentid"=>$this->agent_id,
            "textcard"=> [
                "title"=>$title,
                "description"=>$description,
                "url"=>$url
            ]
        ];
        $postdata = json_encode( $arr, JSON_UNESCAPED_UNICODE );
        $res = $this->postCurl( $postdata, $apiurl );
        return $res;
    }
    /*
    * 发送NEWS消息
    * touser  成员ID列表(消息接收者,多个接收者用‘|’分隔,最多支持1000个)。特殊情况:指定为@all,则向关注该企业应用的全部成员发送
    * toparty 部门ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    * totag  标签ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    * title  标题,不超过128个字节,超过会自动截断
    * description    描述,不超过512个字节,超过会自动截断
    * url    点击后跳转的链接。
    * picurl  图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图640x320,小图80x80。
    */
    public function sendNewsMsg( $title, $description, $url, $picurl, $touser, $toparty='', $totag='' ) {
        $accessToken = $this->getAgentAccessToken();
        //消息接口
        $apiurl = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=$accessToken";
        //文本消息
        $arr = [
            "touser"=>$touser,
            "toparty"=>$toparty,
            "totag"=>$totag,
            "msgtype"=>"news",
            "agentid"=>$this->agent_id,
            "news"=> [
                "articles"=>[
                    [
                    "title"=>$title,
                    "description"=>$description,
                    "url"=>$url,
                    "picurl"=>$picurl
                    ]
                ]
            ]
        ];
        $postdata = json_encode( $arr, JSON_UNESCAPED_UNICODE );
        $res = $this->postCurl( $postdata, $apiurl );
        return $res;
    }
    /*
    * 随机字符串
    */
    public function createNonceStr( $length = 16 ) {
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $str = "";
        for ( $i = 0; $i < $length; $i++ ) {
            $str .= substr( $chars, mt_rand( 0, strlen( $chars ) - 1 ), 1 );
        }
        return $str;
    }
    /**
    * curl get
    */
    public function httpGet( $url ) {
        $oCurl = curl_init();
        if(stripos($url,"https://")!==FALSE){
            curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, FALSE);
            curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
        }
        curl_setopt($oCurl, CURLOPT_URL, $url);
        curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 );
        //curl_setopt($oCurl, CURLOPT_VERBOSE, 1);
        curl_setopt($oCurl, CURLOPT_HEADER, 0);
        $sContent = curl_exec($oCurl);
        // $aStatus = curl_getinfo($oCurl);
        curl_close($oCurl);
        return $sContent;
    }
    /**
    * 以post方式提交到对应的接口url
    */
    public function postCurl( $postdata, $url, $second = 30) {
        $ch = curl_init();
        if(stripos($url,"https://")!==FALSE){
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            curl_setopt($ch, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
        }
        //设置超时
        curl_setopt( $ch, CURLOPT_TIMEOUT, $second );
        curl_setopt( $ch, CURLOPT_URL, $url );
        //设置header
        curl_setopt( $ch, CURLOPT_HEADER, FALSE );
        //要求结果为字符串且输出到屏幕上
        curl_setopt( $ch, CURLOPT_RETURNTRANSFER, TRUE );
        //post提交方式
        curl_setopt( $ch, CURLOPT_POST, TRUE );
        curl_setopt( $ch, CURLOPT_POSTFIELDS, $postdata );
        //运行curl
        $data = curl_exec( $ch );;
        //返回结果
        if ( $data ) {
            curl_close( $ch );
            return $data;
        } else {
            $error = curl_errno( $ch );
            curl_close( $ch );
            throw new \Exception( "curl errno: $error" );
        }
    }
    //测试日志
    public function test($str){
        $uploadDir = realpath(public_path());//物理路径
        $filePath = $uploadDir . DIRECTORY_SEPARATOR . "schedule.txt";
        $handle=fopen($filePath,"a+");
        fwrite($handle, $str.'('.date('m-d H:i:s').') // '.PHP_EOL);
        fclose($handle);
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容