插件代码标准

插件:package.json

必须,插件配置描述文件

{
    "entrance": "",             /*后台管理入口*/
    "mobile-entrance": "",      /*移动后台管理入口*/

    "jump-prefixes": {          /*用于生成跳转 url 并附带 call_token 的链接地址配置项*/
        "common": "",               /*通用地址,如果下述项有未配置的,以 common 为准*/
        "mobile-backend-page": "",  /*后台页跳转地址*/
        "backend-page": ""          /*后台页跳转地址*/
        "page": "",                 /*前台页跳转地址,暂无应用*/
    },

    "proxy-prefixes": {         /*代理配置信息*/
        "common": "",               /*通用地址,如果下述项有未配置的,以 common 为准*/
        "mobile-backend-page": "",  /*后台页转发原始地址*/
        "backend-page": "",         /*后台页转发原始地址*/
        "backend-api": "",          /*后台接口转发原始地址*/
        "page": "",                 /*前台页转发原始地址*/
        "api": ""                   /*前台接口转发原始地址*/
    },

    "oauth-callback-url": ""    /*OAuth 回调地址(必须以https://开头),可不填*/
}

例如:

快站地址 kuaizhan.com ;

某插件 code 为 example,域名为 example.com ;

某快站站点域名为 test.kuaizhan.com;

该插件提交的配置信息如下:

{
    "entrance": "/admin/",
    "mobile-entrance": "/admin/mobile/",

    "jump-prefixes": {
        "mobile-backend-page": "http://m.example.com",
        "backend-page": "http://example.com",
    },

    "proxy-prefixes": {
        "common": "http://example.com",
        "mobile-backend-page": "http://example.com/mobile-backend",
        "backend-page": "http://example.com/backend",
        "backend-api": "http://example.com/bcapi",
        "page": "http://example.com/front_page",
        "api": ""
    }
}

安全验证:call_token

call_token 是快站做上述页面、接口的跳转、转发时,自动生成的一串字符串,用于将当前调用者身份、站点 id、用户 id、时间戳、随机串等信息告诉第三方系统,并会使用约定的 app_keyapp_secret 做签名,以免请求被伪造。 call_token 的计算依赖于具体插件的 app_keyapp_secret ,具体内容请咨询快站开发团队。

call_token 分为 payloadsignature 两部分,完整结构为:payload.signature

其中,payload 是构造字符串 kuaizhan:site_id:user_id:timestamp:nonceurl-safe-base64 计算后的字符串(因调用方是快站,所以第一项为 kuaizhan 如果是第三方调用快站的接口,则第一项应为约定的 app_key)。

signature 则为构造字符串 app_key:site_id:user_id:timestamp:nonce 使用 HMAC-SHA1 算法以约定的 app_secret 为 key 计算后的哈希值,再使用 url-safe-base64 计算后的字符串。请注意计算 signature 时永远使用 app_key 做字符串第一项。

call_token 示例:

a3VhaXpoYW46NzEyODM5NzU5NTozNDoxNDMxNjgyNzU3OlhkQXludWREVUdOd2l4QUU.MmE4ZmIwOGRjZWYxYWJlYmZhOTgwNzdhNDc5YjFkNTUyODBmNzE4MA

其中 payload 部分 decode 之后为:

kuaizhan:7128397595:34:1431682757:XdAynudDUGNwixAE

url-safe-base64 算法为:普通 base64 计算后,用 -_ 符合分别替换 +/ 符号,并去掉结尾的 = 符号。encodedecode 的 php 示例代码(来自 php manual )如下:

function base64url_encode($data) {
    return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}

function base64url_decode($data) {
    return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
}

当采用 iframe 方式嵌入后台页时,call_token 存在于 iframe url 的 query string 中。当采用 proxy 方式调用页面或接口时,快站会在请求第三方时将 call_token 放在 HTTP 的 Cookie 中,键值为 kz_call_token

出于安全考虑,请第三方系统务必验证 call_token 的合法性,包括:

OAuth服务

只适用于提供了 oauth-callback-url 的插件。

数据字典

* <site_id> 快站用户站点ID, BIGINT(10)
* <plugin_id> 插件ID
* <app_key>    由快站分配,用于唯一标识使用OAuth服务的应用
* <app_secret> 有快站分配,用于验证应用身份,切记保密
* <scope_list> 所需权限列表,每个权限是一个固定字符串,每个权限直接以英文空格隔开
* <access_token> oauth服务标识所授予权限的随机唯一字符串,有效期为7天
* <refresh_token> 用于在<access_token>过期时,重新获取<access_token>唯一随机字符串,<refresh_token>有效期为永不过期
* <code> 插件方后台获取<access_token>、<refresh_token>的凭证,是一个随机唯一的字符串,有效期为10分钟,且不可重复使用。

用户授权过程

  1. 将用户重定向至快站账号授权页面/plugin/oauth-authorize?site_id=<site_id>&plugin_id=<plugin_id>&scope=<scope_list>
  2. 用户会在该授权页面上看到插件所请求的权限信息,如果用户同意授权,则输入用户本人账号及密码点击登录授权。
  3. 快站验证用户所输入账号密码如有误,会以弹窗的方式提示用户。如果用户账号及密码验证无误,快站会生成所授权权限对应的<access_token>, <refresh_token> 并生成一个唯一的随机码 <code>, 将用户浏览器重定向到oauth-callback-url 所指定的地址,并带上参数code=<code>
  4. 插件方在oauth-callback-url中调用 /oauth/token 接口获取<access_token>, <refresh_token>,并存储这些token以备用。

scope列表

调用OAuth接口

获取到access_token后,即可使用使用access_token调用相关oauth接口,详见oauth接口文档说明。

刷新access_token

在access_token过期后,需使用refresh_token重新获取access_token,详见接口2.重新获取access_token接口

相关接口列表

1.通过code获取access_token接口
2.重新获取access_token接口
3.获取用户信息接口

组件:基础 package.json

{
    "name": "divider",  /*组件标识,填写组件所在目录的名称*/
    "title": "分隔符",  /*中文名*/
    "image_icon": "",   /*组件的图标*/
    "html": ""          /*用于将用户数据输出为html的模板*/
}

组件:扩展 package.json

说明:在描述了基础package.json之后,如果使用可配置的基类configurableComponent,可以通过添加配置项,自动生成配置框UI,

"data_config": {

    "width": {              /*数据名*/
        "type": "string",   /*数据类型*/
        "required": true,   /*必填*/
        "default": "50%",   /*默认值*/

        "vd_rules": {       /*校验规则*/
            "match": "/^[0-9]{1,3}%$/"
        }
    }
}

关于更多 vd_rules 的规则,参阅 开发API > VD

"widgets": {

    "style":[{                  /*样式选项卡*/
        "data_name":"width",    /*绑定到的data_config 中的name*/
        "label": "宽度",        /*显示的标签*/
        "type": "slider",       /*UI 类型*/
        "opt": {                /* UI 选项,根据不同的UI类型,选项也不同 */
            "min": 0,
            "max": 100,
            "unit": "%"
        }
    }],

    "property":[                /*属性选项卡*/
    ]
}

关于更多 widgets 的规则,参阅 开发API > UI

组件: editing.js

说明:editing.js为编辑器下组件的预览、配置控制类,在提交组件时,必须包括该文件

框架代码如下:

define(['configurableComponent'], function( Component) {
    'use strict';

    //初始化组件类,参数为组件配置,如果组件第一次创建,将传递空配置,如果组件为已经创建到视图窗口,重新加载,将传递已保存的配置

    //覆盖接口函数
    return Component.extend({

    });
});

组件: portal.js

说明:portal.js为发布后加载执行的JS程序,非必须。

框架代码如下:


/*
 *发布后执行JS
 */
define(['zepto'], function($) {
    return {
        //输出到发布页面,当用户正式发布后,调用此函数创建视图。
        onAfterRender: function(el) {

        }
    }
});

"html": "<div  {{{_progdata_}}}></div>",

在页面构建时,这个标签会被替换为组件的 meta 内容

组件: style.css

说明:style.css 为组件的样式文件,在编辑器状态以及发布状态下都会加载,在编写 style.css 时,请参考如下标准:

例如:在插件sys-plugins 中,有组件button. 在编写html结构时,需要如下代码:

<div class="mod-sys-plugins-button"><button class="test-button">按钮</button></div>

对应的样式应该编写如下格式

.mod-sys-plugins-button{

}

.mod-sys-plugins-button .test-button{
    width:80px;
    height:30px;
}

组件: editing.css

说明: editing.css 为在编辑器中特殊的样式,在发布后页面不会加载,在编写 editing.css 时,请参考如下标准:

例如:在插件sys-plugins 中,有组件button. 在编写html结构时,需要如下代码:

<div class="mod-sys-plugins-button"><button class="test-button">按钮</button></div>

如果在预览框需要另外的样式显示,对应的样式应该编写如下格式


.phone-editing .mod-sys-plugins-button{

}

.phone-editing .mod-sys-plugins-button .test-button{
    width:80px;
    height:30px;
}