ionic2/3中http请求的封装和加密

项目要求接口概述:

1.请求协议

  1. HTTP+JSON
  2. HTTPS+JSON

2.接口安全

报文合法性验证

  1. 取出所有参数及值(公共及所有的业务参数),按参数名称的大小写字母序由小到大排列得到A1;
    注:格式如: key1=value1&key2=value2&key3=value3
  2. 将A1 + timestamp拼接为一个字符串,得到A2
    注:如果没有业务参数,则直接用timestamp即可。
  3. 用MD5算法对A2做散列得到A3
  4. 将A3 + userName再拼接成一个字符串,得到A4(如果此时用户未登陆无userName,则为空)
  5. 用MD5算法对A4做散列得到签名值:sign
    注:
  6. MD5(MD5(“key1=value1&key2&value2&key3=value3” + timestamp) + userName)
  7. 散列后的MD5字符数组,按16进制转换成字符串。

需要用到第三方js:



参考地址:https://github.com/xiedajian/ipvpKmfApp2.0/tree/master/src/assets/js

核心代码:

import {Injectable} from '@angular/core';
import {Http, Response, Headers, RequestOptions} from '@angular/http';
import {AES_key, AppConfig}from'../app/app.config';

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';
/*SHA1散列*/
declare function SHA1(msg:string);
/*MD5加密*/
declare function hex_md5(msg:string);
/*AES加密*/
declare var CryptoJS;
/*RSA加密*/
declare var RSAUtils;

/**
 * HTTP请求服务
 */
@Injectable()
export class HttpSer {

    constructor(public http:Http) {
    }

    /**
     * get方式请求
     * @param   url:string  paramObj:{name:'大见',age:'23'}
     * @returns Promise
     */
    get(url:string, paramObj:any = {}) {
        let timestamp = this.getTimestamp();
        let sign = this.getSign(paramObj, timestamp);
        let headers = this.getHeader(sign, timestamp);
        let options = new RequestOptions({headers: headers});
        return this.http.get(url + this.toQueryString(paramObj), options)
            .toPromise()
            .then(this.extractData)
            .catch(this.handleError);
    }

    /**
     * post方式请求
     * @param   url:string  paramObj:{name:'大见',age:'23'}
     * @returns Promise application/x-www-form-urlencoded
     */
    post(url:string, body:any = {}, contentType:string="application/x-www-form-urlencoded") {
        let timestamp = this.getTimestamp();
        let sign = this.getSign(body, timestamp);
        let headers = this.getHeader(sign, timestamp, contentType);
        let options = new RequestOptions({headers: headers});
        return this.http.post(url, this.toBodyString(body), options)
            .toPromise()
            .then(this.extractData)
            .catch(this.handleError);
    }

    /**
     * 登陆App
     * 密码的算法:SHA1(SHA1(密码明文)+请求头中的timestamp)
     * 密码的算法:MD5(MD5(密码明文)+请求头中的timestamp)
     * @param   url:string  body:{userName:'大见',password:'123456'}
     * @returns Promise
     */
    login(url:string, body:any = {}) {
        let timestamp = this.getTimestamp();
        //对密码加密处理
        // let password=SHA1(SHA1(body.password)+timestamp);
        let password = hex_md5(hex_md5(body.password) + timestamp);
        let newbody = {
            userName: body.userName,
            password: password,
        }
        // console.log(url);
        // console.log(newbody);
        let sign = this.getSign(newbody, timestamp);
        let headers = this.getHeader(sign, timestamp);
        let options = new RequestOptions({headers: headers});
        return this.http.post(url, this.toBodyString(newbody), options)
            .toPromise()
            .then(this.extractData)
            .catch(this.handleError);
    }

    /**
     * 修改密码 || 重置密码
     * @param   url:string  body:{userName:'大见',password:'123456',newPassword:'654321'} ||  body:{userName:'大见',newPassword:'654321'}
     * @returns Promise
     * 密码的算法:SHA1(SHA1(密码明文)+请求头中的timestamp)
     * 新密码算法:AES(MD5(密码明文))
     * 注:body两个元素为重置密码,三个元素为修改密码
     */
    setNewPassword(url:string, body:any = {}) {
        let timestamp = this.getTimestamp();
        let newbody:any={};
        let vi = this.getVi(timestamp);
        // console.log(vi);
        let newPassword = this.AES_Encrypt(hex_md5(body.newPassword), vi);
        var arr = Object.keys(body);
        // console.log(body);
        // console.log(arr);
        // console.log(body.length);
        // console.log(arr.length);
        if(arr.length==2){
            newbody = {
                userName: body.userName,
                newPassword: newPassword,
            }
            console.log('重置密码');
        }else {
            let password = hex_md5(hex_md5(body.password) +''+ timestamp);
            newbody = {
                userName: body.userName,
                password: password,
                newPassword: newPassword,
            }
            console.log('修改密码');
        }
        // console.log(vi);
        // console.log(url);
        // console.log(newbody);
        let sign = this.getSign(newbody, timestamp);
        let headers = this.getHeader(sign, timestamp);
        let options = new RequestOptions({headers: headers});
        return this.http.post(url, this.toBodyString(newbody), options)
            .toPromise()
            .then(this.extractData)
            .catch(this.handleError);
    }
    
    /**
     * 获取当前时间 减 2015年1月1日的 时间戳
     */
    private getTimestamp() {
        let timestamp = Math.floor(new Date().getTime() / 1000 - 1420070400).toString();
        return timestamp;
    }

    /**
     * 制作请求头header
     * @param   sign  timestamp
     * @returns headers
     */
    private getHeader(sign:string, timestamp:string, contentType:string="application/x-www-form-urlencoded") {
        let headers:any = new Headers();
        headers.append('content-type', contentType);
        headers.append('token', AppConfig.getToken());
        headers.append('timestamp', timestamp);
        headers.append('platform', AppConfig.getPlatform());
        headers.append('deviceId', AppConfig.getDeviceid());
        headers.append('sign', sign);
        headers.append('appName', AppConfig.getAppName());
        headers.append('appVersion', AppConfig.getAppVersion());
        return headers;
    }

    /**
     *  制作签名
     * @param  obj (请求参数),timestamp
     * @return {string}
     *  1.取出所有参数及值(公共及所有的业务参数),按小写字母序由小到大排列得到A1;
     *  2.将A1 + timestamp拼接为一个字符串,得到A2
     *  3.用SHA1算法对A2做散列得到A3
     *  4.将A3 + userName再拼接成一个字符串,得到A4
     *  5.用SHA1算法对A4做散列得到签名值:sign
     */
    private getSign(obj:any = {}, timestamp:string) {
        let ret:any[] = [];
        for (let key in obj) {
            let values = obj[key];
            if (values && values.constructor == Array) {//数组
                let queryValues = [];
                for (let i = 0, len = values.length, value; i < len; i++) {
                    value = values[i];
                    queryValues.push(this.toSignPair(key, value));
                }
                ret = ret.concat(queryValues);
            } else { //字符串
                ret.push(this.toSignPair(key, values));
            }
        }
        ret.push(this.toSignPair('token', AppConfig.getToken()));
        ret.push(this.toSignPair('platform', AppConfig.getPlatform()));
        ret.push(this.toSignPair('deviceId', AppConfig.getDeviceid()));
        ret.push(this.toSignPair('appName', AppConfig.getAppName()));
        ret.push(this.toSignPair('appVersion', AppConfig.getAppVersion()));
        ret.sort();
        // let A1:string = ret.join('&');
        // let A2 = A1 + '' + timestamp;
        // let A3 = SHA1(A2);
        // let A4 = A3 + AppConfig.getuserName();
        // let sign = SHA1(A4);
        let A1:string = ret.join('&');
        let A2 = A1 + '' + timestamp;
        let A3 = hex_md5(A2);
        let A4 = A3 + AppConfig.getuserName();
        let sign = hex_md5(A4);
         //console.log('token' + '--' + AppConfig.getToken());
         //console.log(ret);
         // console.log('A1' + '--' + A1);
         // console.log('A2' + '--' + A2);
         // console.log('A3' + '--' + A3);
         // console.log('A4' + '--' + A4);
         // console.log('A5' + '--' + sign);
        return sign;
    }

    /**
     * get请求参数处理
     * @param obj 参数对象
     * @return {string} 参数字符串
     * @example
     *  声明: var obj= {'name':'大见',age:23};
     *  调用: toQueryString(obj);
     *  返回: "?name=%E5%B0%8F%E5%86%9B&age=23"
     */
    private toQueryString(obj) {
        let ret = [];
        for (let key in obj) {
            key = encodeURIComponent(key);
            let values = obj[key];
            if (values && values.constructor == Array) {//数组
                let queryValues = [];
                for (let i = 0, len = values.length, value; i < len; i++) {
                    value = values[i];
                    queryValues.push(this.toQueryPair(key, value));
                }
                ret = ret.concat(queryValues);
            } else { //字符串
                ret.push(this.toQueryPair(key, values));
            }
        }
        return '?' + ret.join('&');
    }

    /**
     *  post请求参数处理
     * @param obj
     * @return {string}
     *  声明: var obj= {'name':'大见',age:23};
     *  调用: toQueryString(obj);
     *  返回: "name=%E5%B0%8F%E5%86%9B&age=23"
     */
    private toBodyString(obj) {
        let ret = [];
        for (let key in obj) {
            key = encodeURIComponent(key);
            // key = key;
            let values = obj[key];
            if (values && values.constructor == Array) {//数组
                let queryValues = [];
                for (let i = 0, len = values.length, value; i < len; i++) {
                    value = values[i];
                    queryValues.push(this.toQueryPair(key, value));
                }
                ret = ret.concat(queryValues);
            } else { //字符串
                ret.push(this.toQueryPair(key, values));
            }
        }
        return ret.join('&');
    }

    private toQueryPair(key, value) {
        if (typeof value == 'undefined') {
            return key;
        }
        return key + '=' + encodeURIComponent(value === null ? '' : String(value));
        // return key + '=' +(value === null ? '' : String(value));
    }

    private toSignPair(key, value) {
        return key + '=' + (value === null ? '' : String(value));
    }

    private extractData(res:Response) {
        let body = res.json();
        return body || {};
    }

    private handleError(error:Response | any) {
        let errMsg:string;
        if (error instanceof Response) {
            const body = error.json() || '';
            const err = body.error || JSON.stringify(body);
            errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
        } else {
            errMsg = error.message ? error.message : error.toString();
        }
        console.error(errMsg);
        return Promise.reject(errMsg);
    }


    /**
     * AES加密
     * @param   word:string(需要加密的字符)  iv:string(秘钥偏移量)
     * @returns String
     * 注:需要秘钥(AES_key)和秘钥偏移量(iv)
     */
    public AES_Encrypt(word, iv) {
        var key = CryptoJS.enc.Utf8.parse(AES_key);
        var iv  = CryptoJS.enc.Utf8.parse(iv);
        var srcs = CryptoJS.enc.Utf8.parse(word);
        var encrypted = CryptoJS.AES.encrypt(srcs, key, {
            iv: iv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        });
        return encrypted.ciphertext.toString().toUpperCase();
    }

    /**
     * AES解密
     * @param   word:string(需要解密的字符)  iv:string(秘钥偏移量)
     * @returns String
     * 注:需要秘钥(AES_key)和秘钥偏移量(iv)
     */
    public AES_Decrypt(word, iv) {
        var encryptedHexStr = CryptoJS.enc.Hex.parse(word);
        var srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr);
        var decrypt = CryptoJS.AES.decrypt(srcs, AES_key, {
            iv: iv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        });
        var decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
        return decryptedStr.toString();
    }

    //制作秘钥偏移量(iv)
    /**
     * 制作AES秘钥偏移量(iv)
     * @param   timestamp:string(时间戳) 
     * @returns String
     * 注:iv=timestamp+年月日
     */
    public  getVi(timestamp) {
        let date = new Date();
        let month:any = date.getMonth() + 1;
        let strDate:any = date.getDate();
        if (month >= 1 && month <= 9) {
            month = "0" + month;
        }
        if (strDate >= 0 && strDate <= 9) {
            strDate = "0" + strDate;
        }
        let iv:string = timestamp + "" + date.getFullYear() + "" + month + "" + strDate;
        return iv;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容