易班开放平台授权机制理解以及使用

前言

作为一名使用易班开发平台的技术人员,最常见就是调用易班开发API,获取用户的信息,发送站内信给用户,获取用户的经验和网薪值。当然,在此之前要获取用户的授权(access_token),再去调用接口。

目录

      • 前言
      • 一,易班开放平台是什么?
      • 二,授权流程
        • 1. 授权机制图解
        • 2. 关键步骤
          • 1) 解密
          • 2) 重定向
        • 3. 返回数据说明
          • 1) verify_request的信息
          • 2) 发起获取access_token请求后的信息
          • 3)获取access_token的状态返回
      • 三,PHP Demo
      • 四,易班开放常见API使用
        • 1. 用户基本信息获取
        • 2. 用户校方认证信息获取
        • 3. 常见错误说明
          • e003(非法请求)
          • e004(http请求方式错误 | 无效的授权令牌)
      • 五,根据授权理解自己写授权代码(Node为例)


一,易班开放平台是什么?

要想知道易班开放平台是什么。那么进入易班官网,进入开放平台。再看下面的开发平台介绍

易班开放平台授权机制理解以及使用_第1张图片

所以说,你有一个网站应用,再成为易班的开发者,申请一个应用权限,才可以去调用易班的接口。

二,授权流程

假如有一个【轻应用】信息如下:

AppID : 425fe69a9c75bd98b //解密的向量
AppSceret: 93510b44ede8c4b33b69786eb123934 // 解密的密钥
站内地址: http://f.yiban.cn/iapp243567 // 易班APP里面的应用地址
应用地址:https://www.localhost.com //你的网站应用地址

以下说明都基于这个例子。

1. 授权机制图解

这里假定你已经申请成为易班的开发者,并且在易班开放平台上申请了一个【轻应用】。

用户点击轻应用
带上参数verify_request和yb_uid
网站解密verify_request得到access_token信息
回调
带上参数code
得到access_token
易班APP
应用站内地址
应用实际地址
access_token
是否过期?
重定向易班应用授权页面
用户确定授权
应用站内地址
应用实际地址
使用code发起获取access_token的请求
使用access_token发起获取用户信息请求
调用获取用户信息等接口
  1. 用户在易班APP中的【应用广场】点击你的【轻应用】,进入应用的站内地址。
  2. 易班轻应用框架服务通过get方式在易班客户端webview或浏览器重定向加载应用实际地址,以提供给应用用户授权状态(verify_request)基本信息(yb_uid)数据。
  3. 重定向应用实际地址时,带上参数verify_requestyb_uid。然后网站后台通过AES-256-CBC对称加密算法根据AppID和AppSceret解密verify_request。根据解密后的数据visit_oauth判断是否过期。如果过期需要发起重定向授权。如果没过期则可以使用access_token调用接口。

2. 关键步骤

1) 解密

解密verify_request,要使用AES-128-CBC对称加密算法,AppID作为算法的向量,AppSceret作为算法的密匙。

注意点:

  • AppID和AppSceret如果有问题,则先转化为utf-8格式的字符串
  • verify_request是一段128位的密文(其实长度不止128位,因为有空格在里面),所以解密时,字符串类型的密文需要将其用转化为Hex格式的,再将其转化为Base64编码的格式。再去解密
  • 因为AES-128-CBC对称加密算法是可能有PKCS7Padding或PKCS5Padding补位,所以需要考虑到这个。但是,我试了后,发现易班加密后的字符串是没有补位的,所以不用加补位的解密。
  • 解密出来的是一串JSON字符串,但是后面带着一串空格,所以在格式化为json的时候可能会报错,需要将其空格去掉再去格式化。
  • 如果不能解析verify_request或者不懂解密,则可以用yb_uid来判断。获取用户的access_token状态。
    • 接口:POST(form-data)https://openapi.yiban.cn/oauth/token_info?client_id=应用AppID&yb_uid=用户uid
2) 重定向

服务器重定向到易班授权页面。
接口:https://openapi.yiban.cn/oauth/authorize?client_id=APPID&redirect_uri=应用站内地址&state=你自己设定
state可以不加,如果加了,可以在回调回来之后看是不是那个参数,保证安全。

注意点:

  1. 当使用ajax异步请求的时候,会报错跨域。可以使用window.location.herf = 接口地址进行调用。

3. 返回数据说明

1) verify_request的信息

通过判断json数组中的visit_oauth项的值,来识别来访用户是否已经授权。如果没有授权,则重定向至授权页面引导用户授权。

未授权

{
  "visit_time":访问unix时间戳,
  "visit_user":{
    "userid":"易班用户ID"
  },
  "visit_oauth":false
}

已授权

{
  "visit_time":访问unix时间戳,
  "visit_user":{
    "userid":"易班用户ID",
    "username":"易班用户名",
    "usernick":"易班用户昵称",
    "usersex":"易班用户性别"
  },
  "visit_oauth":{
    "access_token":"授权凭证",
    "token_expires":"有效unix时间戳"
  },
}
2) 发起获取access_token请求后的信息

成功返回

{
  "access_token":"授权凭证",
  "userid":"授权用户id",
  "expires":"截止有效期"
}

失败返回

{
  "status":"error",
  "info":{
    "code":"错误编号",
    "msgCN":"中文报错信息",
    "msgEN":"英文报错信息"
  }
}
3)获取access_token的状态返回

成功返回

{
  "status":"返回状态",
  "userid":"授权用户id",
  "access_token":"用户授权凭证",
  "create_at":"截止有效期",
  "expire_in":"剩余秒数"
}
//返回状态:200-授权有效,404-授权已过期或不存在

失败返回

{
  "status":"error",
  "info":{
    "code":"错误编号",
    "msgCN":"中文报错信息",
    "msgEN":"英文报错信息"
  }
}

三,PHP Demo

根据上面的思路,我们得出下面的代码,这也是易班官方的Demo。
代码思路:

  1. 如果php没有curl模块,json解析模块,解密模块,提醒用户。
  2. 如果没有code,则用户从站内地址而来,解密veridy_request,获取access_token。如果visit_oauth过期,则发起重定向。
  3. 如果有code,则用户重定向回来站内地址,获取access_token

/*
* PHP配置
*/
ini_set("display_errors", "On");
error_reporting(0);
if (!function_exists('curl_init')) {
  throw new Exception('YiBan needs the CURL PHP extension.');
}
if (!function_exists('json_decode')) {
  throw new Exception('YiBan needs the JSON PHP extension.');
}
if (!function_exists('mcrypt_decrypt')) {
  throw new Exception('YiBan needs the mcrypt PHP extension.');
}

/*
* 
*/
//以下三个变量内容需换成本应用的
$APPID = "*****";   //在open.yiban.cn管理中心的AppID
$APPSECRET = "******"; //在open.yiban.cn管理中心的AppSecret
$CALLBACK = "******";  //在open.yiban.cn管理中心的oauth2.0回调地址(站内地址)

if(isset($_GET["code"])){   //用户授权后跳转回来会带上code参数,此处code非access_token,需调用接口转化。
    $getTokenApiUrl = "https://oauth.yiban.cn/token/info?code=".$_GET['code']."&client_id={$APPID}&client_secret={$APPSECRET}&redirect_uri={$CALLBACK}";
    $res = sendRequest($getTokenApiUrl);//发起获取access_token请求
    if(!$res){
        throw new Exception('Get Token Error');
    }
    $userTokenInfo = json_decode($res);//将得到的JOSN结果格式化
    $access_token = $userTokenInfo["access_token"];
}else{
    $postStr = pack("H*", $_GET["verify_request"]);//Hex转化
    //下面是解密
    if(strlen($APPID) == '16') {
        $postInfo = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $APPSECRET, $postStr, MCRYPT_MODE_CBC, $APPID);
    }else {
        $postInfo = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $APPSECRET, $postStr, MCRYPT_MODE_CBC, $APPID);
    }
    $postInfo = rtrim($postInfo);//去除空格
    $postArr = json_decode($postInfo, true);//格式化为Array
    if(!$postArr['visit_oauth']){  //说明该用户未授权需跳转至授权页面
        header("Location: https://openapi.yiban.cn/oauth/authorize?client_id={$APPID}&redirect_uri={$CALLBACK}&display=web");
        die;
    }
    $access_token = $postArr['visit_oauth']['access_token'];//储存access_token
}

//拿到access token了,接下来我们获取当前用户的基本信息试试看,so easy!
$userInfoJsonStr = sendRequest("https://openapi.yiban.cn/user/me?access_token={$access_token}");
$userInfo = json_decode($userInfoJsonStr);

var_dump($userInfo);

function sendRequest($uri){ //发送get请求
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Yi OAuth2 v0.1');
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_ENCODING, "");
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_HEADER, false);
    curl_setopt($ch, CURLOPT_URL, $uri);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array());
    curl_setopt($ch, CURLINFO_HEADER_OUT, true);
    $response = curl_exec($ch);
    return $response;
}

?>

四,易班开放常见API使用

1. 用户基本信息获取

接口:GET https://openapi.yiban.cn/user/me?access_token=用户的授权

成功

{
  "status":"success",
  "info":{
    "yb_userid":"易班用户id",
    "yb_username":"用户名",
    "yb_usernick":"用户昵称",
    "yb_sex":"性别",
    "yb_money":"持有网薪",
    "yb_exp":"经验值",
    "yb_userhead":"用户头像",
    "yb_schoolid":"所在学校id",
    "yb_schoolname":"所在学校名称"
  }
}

失败

{
  "status":"error",
  "info":{
    "code":"错误编号",
    "msgCN":"中文报错信息",
    "msgEN":"英文报错信息"
  }

2. 用户校方认证信息获取

接口: GET https://openapi.yiban.cn/user/verify_me?access_token=用户的授权

成功

{
  "status":"success",
  "info":{
    "yb_userid":"易班用户id",
    "yb_realname":"真实姓名",
    "yb_schoolid":"所在学校id",
    "yb_schoolname":"所在学校名称",
    "yb_collegename":"所在学院名称",
    "yb_classname":"所在班级名称",
    "yb_enteryear":"入学年份",
    "yb_studentid":"学号",
    "yb_examid":"准考证号",
    "yb_admissionid":"录取通知编号",
    "yb_employid":"工号"
  }
}

失败

{
  "status":"error",
  "info":{
    "code":"错误编号",
    "msgCN":"中文报错信息",
    "msgEN":"英文报错信息"
  }
}

3. 常见错误说明

e003(非法请求)

你需要的是等待一下,换一个接口

e004(http请求方式错误 | 无效的授权令牌)

你需要确定接口http请求方法是GET还是POST,并且参数是form-data还是其他的参数格式。

五,根据授权理解自己写授权代码(Node为例)

其实写易班的授权代码挺简单的,只要理解一下几点就能根据自己熟悉的编程语言写了。

  1. 解密verify_request得到access_token
  2. access_token过期,则发起授权重定向
  3. 使用code请求access_token

以上三点就能够自己写获取access_token的授权代码了。

以下是使用在后端用javascript写的授权代码。

const request = require('request'); //请求插件
const CryptoJS = require('crypto-js'); //解密插件

var APPID = "*******";//应用APPID
var APPSECRET = "********";//应用APPSceret

//先格式化密钥和向量
const key = CryptoJS.enc.Utf8.parse(APPSECRET);
const iv = CryptoJS.enc.Utf8.parse(APPID);


const CALLBACK = "http://f.yiban.cn/iapp375894";//应用站内地址
// 获取用户授权的重定向地址
const getCodeUrl = `https://openapi.yiban.cn/oauth/authorize?client_id=${APPID}&redirect_uri=${CALLBACK}`;

//这里也判断有无授权信息

const authorize = (req, res, next) => {
     let CODE = req.query.code; //刚开始用户是否带着令牌code
     let postInfo = req.query.verify_request; //解密
     let uid = req.query.yb_uid;
   
     if (!postInfo) {//不是第一次进入则到下面判断是否有用户信息,没有再跳转。
        next();
        return;
     }

     if (!CODE) {
         postInfo = Decrypt(postInfo); //解密
         postInfo = postInfo.replace(/([^\"\}\}]+)$/g, "");//去除结尾的所有空格
         postInfo = JSON.parse(postInfo);//解析

         if(!postInfo['visit_oauth']) {//未授权
               res.writeHead(302, {'REDIRECT': '/redirect'});
               res.end();//跳转至授权页面
               //res.redirect(getCodeUrl);
               return;
         } else {
            let authorization = {
                userid:postInfo.visit_user.userid,
                access_token:postInfo.visit_oauth.access_token,
                token_expires:postInfo.visit_oauth.token_expires
             }
             //存储授权信息
             req.session.authorization = authorization; 
             next();
         }
         
     } else {
         let getTokenUrl = "https://openapi.yiban.cn/oauth/access_token";
         let params = {
             client_id: APPID,
             client_secret: APPSECRET,
             code: CODE,
             redirect_uri: CALLBACK
         };
         // 发起获取access_token请求
         request.post({
             url: getTokenUrl,
             form: params
         }, (error, response, body) => {
             if (!error && response.statusCode == 200) { //获取access_token
                 let result = JSON.parse(body);
                 if (result.access_token) {
                 		//存储授权信息
                     req.session.authorization = result;
                     next();  
                 } else {
                    console.log("请求错误",result.info.code);
                    res.json({
                        status:"1",
                        msg:"请求错误",
                        reult:[]
                    });
                 }
             } else {
                 console.warn("请求错误");
                  res.json({
                        status:"1",
                        msg:"请求错误",
                        reult:[]
                    });
             }
         });
     }
}

const Decrypt = (word) => {//解密模块
    //由于加密后的密文为128位的字符串,那么解密时,需要将其转为Base64编码的格式。
    // 拿到字符串类型的密文需要先将其用Hex方法parse一下
    let encryptedHexStr = CryptoJS.enc.Hex.parse(word);//
    let srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr); // 只有Base64类型的字符串密文才能对其进行解密
    let decrypt = CryptoJS.AES.decrypt(srcs, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.ZeroPadding//第三方加密没有偏移
    });
    let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
    return decryptedStr.toString();
}

module.exports = authorize;

你可能感兴趣的:(web应用开发)