| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595 |
- /**
- * OAUTH2 授权
- * 登录,用户授权
- * <pre>
- * 作者:hugh zhuang
- * 邮箱:3378340995@qq.com
- * 日期:2018-10-08-下午3:29:34
- * 版权:广州流辰信息技术有限公司
- * </pre>
- */
- import { OAUTH2_URL } from "@/api/baseUrl";
- import request from "@/utils/request";
- import requestState from "@/constants/state";
- import { Message } from "element-ui";
- import qs from "qs";
- var AccessToken = function (data) {
- if (!(this instanceof AccessToken)) {
- return new AccessToken(data);
- }
- this.data = data;
- };
- /**
- * 对返回结果的一层封装,如果遇见IBPS平台返回的错误,将返回一个错误
- * 参见:IBPS返回码说明
- */
- var wrapper = function (callback) {
- return function (err, data, res) {
- callback = callback || function () {};
- if (err) {
- err.name = "IBPSAPI" + err.name;
- return callback(err, data, res);
- }
- callback(null, data, res);
- };
- };
- /*!
- * 检查AccessToken是否有效,检查规则为当前时间和过期时间进行对比
- *
- * Examples:
- * ```
- * token.isValid();
- * ```
- */
- AccessToken.prototype.isValid = function () {
- return (
- !!this.data.access_token &&
- new Date().getTime() < this.data.create_at + this.data.expires_in * 1000
- );
- };
- /*!
- * 处理token,更新过期时间
- */
- var processToken = function (that, callback) {
- var createAt = new Date().getTime();
- return function (err, data, res) {
- if (err) {
- return callback(err, data, res);
- }
- data.create_at = createAt;
- if (res.variables && res.variables.licJson) {
- data.licJson = JSON.parse(res.variables.licJson);
- }
- // 存储token
- that.saveToken(data.uid, data, function (err) {
- callback(err, new AccessToken(data));
- });
- };
- };
- /**
- * 根据clientId和clientSecret创建OAuth接口的构造函数
- * 如需跨进程跨机器进行操作,access token需要进行全局维护
- * 使用token的优先级是:
- *
- * 1. 使用当前缓存的token对象
- * 2. 调用开发传入的获取token的异步方法,获得token之后使用(并缓存它)。
- * Examples:
- * ```
- * import IbpsOAuth from '@/utils/oauth2'
- * var oauthApi = new OAuth('clientId', 'clientSecret');
- * ```
- * @param {String} clientId 在平台上申请得到的clientId(或appid)
- * @param {String} clientSecret 在平台上申请得到的client secret(或app secret)
- * @param {Function} getToken 用于获取token的方法
- * @param {Function} saveToken 用于保存token的方法
- */
- var OAuth = function (clientId, clientSecret, getToken, saveToken) {
- this.clientId = clientId;
- this.clientSecret = clientSecret;
- this.statistic = "";
- this.username = "";
- // token的获取和存储
- this.store = {};
- this.getToken =
- getToken ||
- function (uid, callback) {
- callback(null, this.store[uid]);
- };
- if (!saveToken && process.env.NODE_ENV === "production") {
- console.warn(
- "Please dont save oauth token into memory under production"
- );
- }
- this.saveToken =
- saveToken ||
- function (uid, token, callback) {
- this.store[uid] = token;
- callback(null);
- };
- this.defaults = {};
- };
- /*!
- * request的封装
- *
- * @param {String} url 路径
- * @param {Object} opts urllib选项
- * @param {Function} callback 回调函数
- */
- OAuth.prototype.request = function (opts, callback) {
- const options = {};
- Object.assign(options, this.defaults);
- if (typeof opts === "function") {
- callback = opts;
- opts = {};
- }
- for (const key in opts) {
- if (key !== "headers") {
- options[key] = opts[key];
- } else {
- if (opts.headers) {
- options.headers = options.headers || {};
- Object.assign(options.headers, opts.headers);
- }
- }
- }
- request(options)
- .then((response) => {
- const { state } = response;
- if (
- state === requestState.UNSUPORT ||
- state === requestState.WARNING
- ) {
- const err = new Error(response.message);
- err.state = state;
- err.cause = response.cause;
- callback(err);
- } else {
- callback(null, response.data, response);
- }
- })
- .catch((error) => {
- callback(error);
- });
- };
- /**
- * 获取授权页面的URL地址
- * @param {String} redirect 授权后要跳转的地址
- * @param {String} state 开发者可提供的数据
- * @param {String} scope 作用范围,值为snsapi_userinfo和snsapi_base,前者用于弹出,后者用于跳转
- */
- OAuth.prototype.getAuthorizeURL = function (redirect, state, scope) {
- const url = OAUTH2_URL() + "";
- const info = {
- clientId: this.clientId,
- redirect_uri: redirect,
- response_type: "code",
- scope: scope || "snsapi_base",
- state: state || "",
- };
- return url + "?" + qs.stringify(info) + "#ibps_redirect";
- };
- /**
- * 获取授权页面的URL地址
- * @param {String} redirect 授权后要跳转的地址
- * @param {String} state 开发者可提供的数据
- * @param {String} scope 作用范围,值为snsapi_login,前者用于弹出,后者用于跳转
- */
- OAuth.prototype.getAuthorizeURLForWebsite = function (redirect, state, scope) {
- const url = OAUTH2_URL() + "/qrconnect";
- const info = {
- clientId: this.clientId,
- redirect_uri: redirect,
- response_type: "code",
- scope: scope || "snsapi_login",
- state: state || "",
- };
- return url + "?" + qs.stringify(info) + "#ibps_redirect";
- };
- /**
- * 根据授权获取到的code,换取access_token和uid
- * 获取uid之后,可以调用`IBPS.API`来获取更多用户信息
- * Examples:
- * ```
- * api.getAccessTokenByCode(code, callback);
- * ```
- * Callback:
- *
- * - `error`, 获取access token出现异常时的异常对象
- * - `result`, 成功时得到的响应结果
- *
- * Result:
- * ```
- * {
- * data: {
- * "access_token": "ACCESS_TOKEN",
- * "refresh_token": "REFRESH_TOKEN",
- * "uid": "uid",
- * "expires_in": 7200,
- * "scope": "SCOPE"
- * }
- * }
- * ```
- * @param {String} code 授权获取到的code
- * @param {Function} callback 回调函数
- */
- OAuth.prototype.getAccessTokenByCode = function (code, callback) {
- localStorage.setItem("username", this.username);
- const args = {
- url: OAUTH2_URL() + "/authentication/apply",
- data: {
- client_id: this.clientId,
- client_secret: this.clientSecret,
- authorize_code: code,
- username: this.username,
- grant_type: "authorization_code",
- },
- method: "post",
- };
- this.request(args, wrapper(processToken(this, callback)));
- };
- /**
- * 密码授权模式
- * 根据用户名和密码,换取access token和uid
- * 获取uid之后,可以调用`IBPS.API`来获取更多用户信息
- * Examples:
- * ```
- * api.getAccessTokenByPassword(code, callback);
- * ```
- * Callback:
- *
- * - `error`, 获取access token出现异常时的异常对象
- * - `result`, 成功时得到的响应结果
- *
- * Result:
- * ```
- * {
- * data: {
- * "access_token": "ACCESS_TOKEN",
- * "refresh_token": "REFRESH_TOKEN",
- * "uid": "uid",
- * "expires_in": 7200,
- * "scope": "SCOPE"
- * }
- * }
- * ```
- * ```
- * @param {String} username 用户名
- * @param {String} password 密码
- * @param {Function} callback 回调函数
- */
- OAuth.prototype.getAccessTokenByPassword = function (
- { username, password },
- callback
- ) {
- const args = {
- url: OAUTH2_URL() + "/authentication/apply",
- data: {
- client_id: this.clientId,
- client_secret: this.clientSecret,
- username: username,
- password: password,
- grant_type: "password_credentials",
- },
- method: "post",
- };
- this.request(args, wrapper(processToken(this, callback)));
- };
- /**
- * 根据refresh token,刷新access token,调用getAccessTokenByCode后才有效
- * Examples:
- * ```
- * api.refreshAccessToken(refreshToken, callback);
- * ```
- * Callback:
- *
- * - `err`, 刷新access token出现异常时的异常对象
- * - `result`, 成功时得到的响应结果
- *
- * Result:
- * ```
- * {
- * data: {
- * "access_token": "ACCESS_TOKEN",
- * "expires_in": 7200,
- * "refresh_token": "REFRESH_TOKEN",
- * "uid": "uid",
- * "remind_in": 7
- * }
- * }
- * ```
- * @param {String} refreshToken 刷新tonken
- * @param {Function} callback 回调函数
- */
- OAuth.prototype.refreshAccessToken = function (refreshToken, callback) {
- const username = localStorage.getItem("username");
- const args = {
- url: OAUTH2_URL() + "/authentication/apply",
- data: {
- client_id: this.clientId,
- client_secret: this.clientSecret,
- grant_type: "refresh_token",
- username,
- refresh_token: refreshToken,
- },
- method: "post",
- };
- this.request(args, wrapper(processToken(this, callback)));
- };
- /**
- * 获取用户信息 【私有方法】
- * @param {*} options
- * @param {*} accessToken
- * @param {*} callback
- */
- OAuth.prototype._getUser = function (options, accessToken, callback) {
- const args = {
- url: OAUTH2_URL() + "/user/context",
- data: {
- access_token: accessToken,
- uid: options.uid,
- lang: options.lang || "zh_CN",
- },
- };
- this.request(args, wrapper(callback));
- };
- /**
- * 根据uid,获取用户信息。
- * 当access token无效时,自动通过refresh token获取新的access token。然后再获取用户信息
- * Examples:
- * ```
- * api.getUser(uid, callback);
- * api.getUser(options, callback);
- * ```
- *
- * Options:
- * ```
- * // 或
- * {
- * "uid": "the user Id", // 必须
- * "lang": "the lang code" // zh_CN 简体,zh_TW 繁体,en 英语
- * }
- * ```
- * Callback:
- *
- * - `err`, 获取用户信息出现异常时的异常对象
- * - `result`, 成功时得到的响应结果
- *
- * Result:
- * ```
- * {
- * "uid": "uid",
- * "nickname": "NICKNAME",
- * "sex": "1",
- * "province": "PROVINCE"
- * "city": "CITY",
- * "country": "COUNTRY",
- * "headimgurl": "http://xxxxx.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
- * "privilege": [
- * "PRIVILEGE1"
- * "PRIVILEGE2"
- * ]
- * }
- * ```
- * @param {Object|String} options 传入uid或者参见Options
- * @param {Function} callback 回调函数
- */
- OAuth.prototype.getUser = function (options, callback) {
- if (typeof options !== "object") {
- options = {
- uid: options,
- };
- }
- const that = this;
- this.getToken(options.uid, function (err, data) {
- if (err) {
- return callback(err);
- }
- // 没有token数据
- if (!data) {
- const message =
- "No token for " + options.uid + ", please authorize first.";
- Message({
- message: `${message}`,
- type: "error",
- showClose: true,
- dangerouslyUseHTMLString: true,
- duration: 5 * 1000,
- });
- const error = new Error(message);
- err.state = "NoOAuthTokenError";
- return callback(error);
- }
- const token = new AccessToken(data);
- if (token.isValid()) {
- that._getUser(options, token.data.access_token, callback);
- } else {
- that.refreshAccessToken(
- token.data.refresh_token,
- function (err, token) {
- if (err) {
- return callback(err);
- }
- that._getUser(options, token.data.access_token, callback);
- }
- );
- }
- });
- };
- /**
- * 检验授权凭证(access_token)是否有效。
- * Examples:
- * ```
- * api.verifyToken(uid, accessToken, callback);
- * ```
- * @param {String} uid 传入uid
- * @param {String} accessToken 待校验的access token
- * @param {Function} callback 回调函数
- */
- OAuth.prototype.verifyToken = function (uid, accessToken, callback) {
- const args = {
- url: OAUTH2_URL() + "/authentication/verify",
- params: {
- access_token: accessToken,
- uid: uid,
- },
- method: "post",
- };
- this.request(args, wrapper(callback));
- };
- /**
- * 用户名、密码方式登录。
- * Examples:
- * ```
- * api.userLogin(data, callback);
- * ```
- * @param {Objcct} data
- * username : 用户名
- * password : 密码
- * @param {Function} callback 回调函数
- */
- OAuth.prototype.userLogin = function (data, callback) {
- const args = {
- url: OAUTH2_URL() + "/user/login/apply",
- data: data,
- method: "post",
- };
- this.request(args, wrapper(callback));
- };
- /**
- *
- *申请授权
- * Examples:
- * ```
- * api.authorize(login, callback);
- * ```
- * @param {Objcct} options
- * @param {Function} callback 回调函数
- */
- OAuth.prototype.authorize = function (data, callback) {
- const url = OAUTH2_URL() + "/authorize/apply";
- if (typeof data !== "object") {
- data = {
- login_state: data,
- };
- }
- data.client_id = this.clientId;
- const args = {
- url,
- data: data,
- method: "post",
- };
- this.request(args, wrapper(callback));
- };
- /**
- * 根据code,获取用户信息。
- * Examples:
- * ```
- * api.getUserByCode(code, callback);
- * ```
- * Callback:
- *
- * - `err`, 获取用户信息出现异常时的异常对象
- * - `result`, 成功时得到的响应结果
- *
- * Result:
- * ```
- * {
- * "uid": "uid",
- * "nickname": "NICKNAME",
- * "sex": "1",
- * "province": "PROVINCE"
- * "city": "CITY",
- * "country": "COUNTRY",
- * "headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
- * "privilege": [
- * "PRIVILEGE1"
- * "PRIVILEGE2"
- * ]
- * }
- * ```
- * @param {Object|String} options 授权获取到的code
- * @param {Function} callback 回调函数
- */
- OAuth.prototype.getUserByCode = function (options, callback) {
- const that = this;
- let lang;
- let code;
- if (typeof options === "string") {
- code = options;
- } else {
- lang = options.lang;
- code = options.code;
- }
- this.getAccessTokenByCode(code, function (err, result) {
- if (err) {
- return callback(err);
- }
- const uid = result.data.uid;
- that.getUser({ uid: uid, lang: lang }, callback);
- });
- };
- /**
- * 通过登录获取access_token
- * @param {*} options
- * @param {*} callback
- */
- OAuth.prototype.getLoginCode = function (options, callback) {
- this.username = options.username;
- const that = this;
- /**
- * 用户登录
- */
- this.userLogin(options, function (err, data, res) {
- if (err) {
- return callback(err);
- }
- that.statistic = res.variables.statistic; //判斷是否有统计权限
- // 没有token数据
- if (!data) {
- const message = "没有传回用户信息";
- Message({
- message: `${message}`,
- type: "error",
- showClose: true,
- dangerouslyUseHTMLString: true,
- duration: 5 * 1000,
- });
- const error = new Error(message);
- err.state = "NoOAuthTokenError";
- return callback(error);
- }
- that.authorize(data, function (err1, data1) {
- if (err1) {
- return callback(err1);
- }
- that.getAccessTokenByCode(data1, callback);
- });
- });
- };
- export default OAuth;
|