PHP第三方登录学习笔记

一、OAuth2.0

(一)什么是OAuth

全称为Open Authorization,即开放式授权。
OAuth协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是OAuth的授权不会使第三方触及到用户的账户信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此OAuth是安全的。

(二)OAuth的工作原理

PHP第三方登录学习笔记_第1张图片

(三)OAuth的应用场景

  • QQ用户授权慕课网使用其QQ账号相关的信息
  • 获取授权后,在符合权限规则的情况下访问各种API

(四)三个重要步骤

步骤一:请求OAuth登录页
Request Token URL:未授权的令牌请求服务地址
(带有特定参数的URL,如AppID、AppKey、回调地址)
步骤二:用户使用第三方账号登录并授权
第三方账号登录成功后,会跳转到指定的回调地址,并带上一个GET参数code,这个code是会过期的,有效期非常短,并且只可以使用一次。
步骤三:返回登录结果
User Authorization URL:用户授权的令牌请求服务地址
用户QQ登录授权之后需要请求一个带有特定参数的URL(此时用户已授权)
这里写图片描述
请求验证通过之后会得到一个响应数据,从这个相应数据可以知道这个用户的昵称、头像等基本账号信息。

(五)关于AccessToken

AccessToken:用户通过第三方应用访问OAuth接口的令牌
相应数据里面包含AccessToken,有了它,第三方站点就可以以用户的身份执行OAuth服务方允许执行的操作,如:分享QQ空间。

(六)AccessToken和Refresh Token

1、数据传输原理

访问开放平台的接口实质上都是通过第三方应用拼接一个特定的URL来访问API的。即使是连续几次访问同一个API接口,动态拼接的URL也有可能是不一样的,即任意一次访问一个API都需要重新拼接一个URL,而且每次都需要用上AccessToken。出于安全考虑,一般都是使用POST发起HTTP请求。开放平台再将数据打包成xml/json返回。
PHP第三方登录学习笔记_第2张图片

2、生命周期解析

AccessToken有生命周期,较长(10天半个月甚至更长)。
如果AccessToken过期了,
(1)重新授权登录第三方站点
(2)User Authorization URL中指定参数need_refresh_token=true(不同开放平台叫法不一样)指明返回时携带Refresh Token参数。当AccessToken快过期时,就可以使用Refresh Token动态拼接URL请求获得一个新的AccessToken。
Refresh Token也有生命周期,更长(几个月半年甚至更长)。

二、第三方登录——QQ登录

(一)前置条件

  • 一个QQ号
  • 一台公网通过域名可访问的web服务器(没有域名无法申请到AppID)
  • 关于备案
    下面表格0表示免备案,1表示必须备案:
服务器 \ 用途 开发练手 发布上线
中国大陆 腾讯=0 0 | 1 = 1 腾讯=1 1 | 1 = 1
工信部=1 工信部=1
港澳台及国外 腾讯=0 0 | 0 =0 腾讯=1 1 | 0 =1
工信部=0 工信部=0

(二)申请AppID和AppKey

QQ互联:https://connect.qq.com/
登录,点击应用管理,填写资料,邮箱验证,完成注册。完成之后就可以进去创建应用了。
创建过程中注意验证步骤:
PHP第三方登录学习笔记_第3张图片

(三)引入官方SDK

SDK是官方提供的接入QQ登录的示例代码。
SDK下载:http://wiki.connect.qq.com/sdk%E4%B8%8B%E8%BD%BD
SDK参数配置:访问SDK的install目录,根据要求填写表单。
请求授权列表中:get_user_info是获取用户基本信息
勾选的权限会在登录页面中展示:
PHP第三方登录学习笔记_第4张图片
配置成功之后,只保留API目录即可。

(四)SDK解读

文档资料:http://wiki.connect.qq.com/
PHP第三方登录学习笔记_第5张图片
SDK核心类和重要方法
1、登录授权相关的三个主要类(API/class/*.class.php)
Recorder.class.php:配置读取与SESSION存取
URL.class.php:基于CURL库的get与post请求
Oauth.class.php:Oauth相关URL动态拼接与token操作
Recorder.class.php:

  • __construct()
$incFileContents = file(ROOT."comm/inc.php");//读入配置文件
$incFileContents = $incFileContents[1];
$this->inc = json_decode($incFileContents);//解析成php对象
  • readInc($name)
return $this->inc->$name;
//->readInc('appid')即读取配置文件的appid

URL.class.php:

  • combineURL( baseURL, b a s e U R L , keysArr)
$combined = $baseURL."?";//拼接?
foreach($keysArr as $key => $val){
   $valueArr[] = "$key=$val";//拼接参数
}
$keyStr = implode("&",$valueArr);//使用&拼接参数键值对
  • get( url, u r l , keysArr) 发送get请求
  • post( url, u r l , keysArr, $flag = 0) 发送post请求

Oauth.class.php:

  • qq_login() 拼接QQ登录页面URL
$appid = $this->recorder->readInc("appid");//读取appid
$callback = $this->recorder->readInc("callback");//读取回调地
$scope = $this->recorder->readInc("scope");//读取授权列表

//-------生成唯一随机串防CSRF攻击
$state = md5(uniqid(rand(), TRUE));//原样返回参数
$this->recorder->write('state',$state);//state写入session中

//-------构造请求参数列表
$keysArr = array(
    "response_type" => "code",
    "client_id" => $appid,
    "redirect_uri" => $callback,
    "state" => $state,
    "scope" => $scope
);

//拼接URL之后
$login_url =  $this->urlUtils->combineURL(self::GET_AUTH_CODE_URL, $keysArr);
header("Location:$login_url");//跳转到生成的url
  • qq_callback() QQ登录完成后的回调处理
$state = $this->recorder->read("state");

//--------验证state防止CSRF攻击
if(!$state || $_GET['state'] != $state){//返回的state和本地的不一致抛出错误提示
    $this->error->showError("30001");
}

//State参数是可选的
//为数据传输再添加一道安全保障

//-------请求参数列表
$keysArr = array(
    "grant_type" => "authorization_code",
    "client_id" => $this->recorder->readInc("appid"),
    "redirect_uri" => urlencode($this->recorder->readInc("callback")),
    "client_secret" => $this->recorder->readInc("appkey"),
    "code" => $_GET['code']
);

//------构造请求access_token的url
$token_url = $this->urlUtils->combineURL(self::GET_ACCESS_TOKEN_URL, $keysArr);
$response = $this->urlUtils->get_contents($token_url);

(五)SDK优化

  • 调整文件及目录结构
  • SDK中的常量名太常见可能和现有项目冲突,批量替换SDK中的常量名称为不常见名称

(六)开发

首页index.php:


require_once 'Connect2.1/qqConnectAPI.php';
?>

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Documenttitle>
head>
<body>
     if (!isset($_COOKIE['qq_accesstoken']) && !isset($_COOKIE['qq_openid'])){ ?>
    <a href="qqlogin.php">QQ登录a>
     }else{ ?>
    <a href="qqlogout.php">退出QQa>
    
        $qc=new QC($_COOKIE['qq_accesstoken'],$_COOKIE['qq_openid']);
        $userinfo=$qc->get_user_info();
        var_dump($userinfo);
    } ?>
body>
html>

申请上线需要使用官网提供的QQ登录按钮素材。
QQ登录页面qqlogin.php:

require_once 'Connect2.1/qqConnectAPI.php';

//访问QQ登录页面
$oauth=new Oauth();
$oauth->qq_login();

回调地址页面callback.php:

require_once 'Connect2.1/qqConnectAPI.php';

//请求access token
$oauth=new Oauth();
$accessToken=$oauth->qq_callback();
//获取openID
//QQ用户在第三方站点的唯一标识
//同一个QQ用户在不同站点使用QQ登录openID始终一样
$openID=$oauth->get_openid();

setcookie('qq_accesstoken',$accessToken,time()+86400);//时间要比access token的有效期短
setcookie('qq_openid',$openID,time()+86400);

header('Location: index.php');

退出页面qqlogout.php:

setcookie('qq_accesstoken',null);
setcookie('qq_openid',null);

你可能感兴趣的:(后台开发)