Prechádzať zdrojové kódy

feat 添加微信登录和token认证

tumobi 7 rokov pred
rodič
commit
859056a761

+ 1 - 0
package.json

@@ -12,6 +12,7 @@
     "babel-runtime": "6.x.x",
     "cheerio": "^0.22.0",
     "gm": "^1.23.0",
+    "jsonwebtoken": "^7.4.1",
     "lodash": "^4.17.4",
     "moment": "^2.18.1",
     "redis": "^2.3.0",

+ 6 - 6
src/api/controller/address.js

@@ -8,7 +8,7 @@ export default class extends Base {
    * @return {Promise} []
    */
   async listAction(){
-    let addressList = await this.model('address').where({user_id: 1}).select();
+    let addressList = await this.model('address').where({user_id: think.userId}).select();
     let itemKey = 0;
     for ( let addressItem of addressList) {
         addressList[itemKey].province_name = await this.model('region').getRegionName(addressItem.province_id);
@@ -29,7 +29,7 @@ export default class extends Base {
    */
   async detailAction(){
     let addressId = this.get('id');
-    let addressInfo = await this.model('address').where({user_id: 1, id: addressId}).find();
+    let addressInfo = await this.model('address').where({user_id: think.userId, id: addressId}).find();
     if ( !think.isEmpty(addressInfo)) {
       addressInfo.province_name = await this.model('region').getRegionName(addressInfo.province_id);
       addressInfo.city_name = await this.model('region').getRegionName(addressInfo.city_id);
@@ -55,19 +55,19 @@ export default class extends Base {
       city_id: this.post('city_id'),
       district_id: this.post('district_id'),
       address: this.post('address'),
-      user_id: 1,
+      user_id: getLoginUserId(),
       is_default: this.post('is_default') == true ? 1 : 0
     };
 
     if (think.isEmpty(addressId)) {
       addressId = await this.model('address').add(addressData);
     } else {
-      await this.model('address').where({id: addressId, user_id: 1}).update(addressData);
+      await this.model('address').where({id: addressId, user_id: think.userId}).update(addressData);
     }
 
     //如果设置为默认,则取消其它的默认
     if (this.post('is_default') == true) {
-        await this.model('address').where({id: ['<>', addressId], user_id: 1}).update({
+        await this.model('address').where({id: ['<>', addressId], user_id: think.userId}).update({
             is_default: 0
         });
     }
@@ -84,7 +84,7 @@ export default class extends Base {
   async deleteAction(){
     let addressId = this.post('id');
 
-    await this.model('address').where({id: addressId, user_id: 1}).delete();
+    await this.model('address').where({id: addressId, user_id: think.userId}).delete();
 
     return this.success('删除成功');
   }

+ 27 - 16
src/api/controller/auth.js

@@ -18,10 +18,11 @@ export default class extends Base {
     return this.success(avatar_path);
   }
 
-  async loginAction() {
+  async loginByWeixinAction() {
 
     let code = this.post('code');
-    let userInfo = this.post('userInfo');
+    let fullUserInfo = this.post('userInfo');
+    let userInfo = fullUserInfo.userInfo;
 
     //获取openid
     let options = {
@@ -38,26 +39,32 @@ export default class extends Base {
     let sessionData = await rp(options);
 
 
-    //下载微信用户的头像到本地
-    // let avatar_path = think.RESOURCE_PATH + '/static/user/avatar/1.' + _.last(_.split('https://img6.bdstatic.com/img/image/smallpic/liutaoxiaotu.jpg', '.'));
-    // rp('https://img6.bdstatic.com/img/image/smallpic/liutaoxiaotu.jpg').pipe(fs.createWriteStream(avatar_path));
     sessionData = JSON.parse(sessionData);
     if (!sessionData.openid) {
       return this.fail('登录失败');
     }
 
-    //根据openid查找用户是否已经注册
-    let userId = await this.model('user').where({weixin_openid: sessionData.openid}).getField('id', true);
+    //验证用户信息完整性
+    const crypto = require('crypto');
+    const sha1 = crypto.createHash('sha1').update(fullUserInfo.rawData + sessionData.session_key).digest('hex');
+    if (fullUserInfo.signature !== sha1) {
+      return this.fail('登录失败');
+    }
+
+    // 根据openid查找用户是否已经注册
+    let userId = await this.model('user').where({ weixin_openid: sessionData.openid }).getField('id', true);
     if (think.isEmpty(userId)) {
       //注册
       userId = await this.model('user').add({
-        username: '微信用户' + sessionData.openid.substr(0, 6),
+        username: '微信用户' + think.uuid(6),
         password: sessionData.openid,
         register_time: parseInt(new Date().getTime() / 1000),
         register_ip: this.ip(),
+        last_login_time: parseInt(new Date().getTime() / 1000),
+        last_login_ip: this.ip(),
         weixin_openid: sessionData.openid,
         avatar: userInfo.avatarUrl,
-        sex: userInfo.gender, //性别 0:未知、1:男、2:女
+        gender: userInfo.gender, //性别 0:未知、1:男、2:女
         nickname: userInfo.nickName
       });
     }
@@ -65,22 +72,26 @@ export default class extends Base {
     sessionData.user_id = userId;
 
     //查询用户信息
-    let newUserInfo = await this.model('user').field(['id', 'username', 'nickname', 'gender', 'avatar', 'birthday']).where({id: userId}).find();
+    let newUserInfo = await this.model('user').field(['id', 'username', 'nickname', 'gender', 'avatar', 'birthday']).where({ id: userId }).find();
 
-    let sessionKey = think.uuid(128);
+    //更新登录信息
+    userId = await this.model('user').where({ id: userId }).update({
+      last_login_time: parseInt(new Date().getTime() / 1000),
+      last_login_ip: this.ip(),
+    });
+
+    let TokenSerivce = this.service('token');
+    let tokenObj = new TokenSerivce();
+    let sessionKey = await tokenObj.create(sessionData);
 
     if (think.isEmpty(newUserInfo) || think.isEmpty(sessionKey)) {
       return this.fail('登录失败');
     }
 
-    //保存openid到redis
-    await think.cache(sessionKey, sessionData, {timeout: 5400});
-
-    return this.success({token: sessionKey, userInfo: newUserInfo});
+    return this.success({ token: sessionKey, userInfo: newUserInfo });
   }
 
   async logoutAction() {
-    await think.cache(this.header('token'), null);
     return this.success();
   }
 }

+ 20 - 1
src/api/controller/base.js

@@ -1,7 +1,26 @@
 'use strict';
 
 export default class extends think.controller.base {
+
   /**
-   * some base method in here
+   * 前置操作
    */
+  async __before() {
+
+    think.token = this.header('X-Nideshop-Token') || '';
+    if (!think.isEmpty(think.token)) {
+      let TokenSerivce = this.service('token');
+      let tokenObj = new TokenSerivce();
+      let sessionInfo = await tokenObj.parse();
+
+      console.log(sessionInfo)
+      if (!think.isEmpty(sessionInfo) && sessionInfo.user_id > 0) {
+        think.userId = sessionInfo.user_id;
+      } else {
+        think.userId = 0;
+      }
+    } else {
+      think.userId = 0;
+    }
+  }
 }

+ 4 - 4
src/api/controller/cart.js

@@ -9,7 +9,7 @@ export default class extends Base {
    * @returns {Promise.<{cartList: *, cartTotal: {goodsCount: number, goodsAmount: number, checkedGoodsCount: number, checkedGoodsAmount: number}}>}
    */
   async getCart(){
-    let cartList = await this.model('cart').where({user_id: 1, session_id: 1}).select();
+    let cartList = await this.model('cart').where({user_id: think.userId, session_id: 1}).select();
 
     //获取购物车统计信息
     let goodsCount = 0;
@@ -90,7 +90,7 @@ export default class extends Base {
         list_pic_url: goodsInfo.list_pic_url,
         number: number,
         session_id: 1,
-        user_id: 1,
+        user_id: think.userId,
         retail_price: productInfo.retail_price,
         market_price: productInfo.retail_price,
         goods_specifition_name_value: goodsSepcifitionValue.join(';'),
@@ -238,7 +238,7 @@ export default class extends Base {
     let couponId = this.get('couponId');    //使用的优惠券id
 
     //选择的收货地址
-    let checkedAddress = await this.model('address').where({is_default: 1}).find();
+    let checkedAddress = await this.model('address').where({is_default: 1, user_id: think.userId}).find();
     if ( !think.isEmpty(checkedAddress)) {
       checkedAddress.province_name = await this.model('region').getRegionName(checkedAddress.province_id);
       checkedAddress.city_name = await this.model('region').getRegionName(checkedAddress.city_id);
@@ -256,7 +256,7 @@ export default class extends Base {
     });
 
 
-    //获取可用的优惠券信息
+    //获取可用的优惠券信息,功能还示实现
     let couponList = await this.model('user_coupon').select();
     let couponPrice = 0.00;  //使用优惠券减免的金额
 

+ 10 - 3
src/api/controller/collect.js

@@ -3,6 +3,13 @@
 import Base from './base.js';
 
 export default class extends Base {
+
+  async __before() {
+    if (think.userId <= 0) {
+      return this.fail(401, '请先登录');
+    }
+  }
+
   /**
    * index action
    * @return {Promise} []
@@ -24,7 +31,7 @@ export default class extends Base {
         join: 'left', //join 方式,有 left, right, inner 3 种方式
         as: 'g', // 表别名
         on: ['c.value_id', 'g.id'] //ON 条件
-      }).where({user_id: getLoginUserId(), type_id: typeId}).countSelect();
+      }).where({user_id: think.userId, type_id: typeId}).countSelect();
 
 
     return this.success(list);
@@ -34,7 +41,7 @@ export default class extends Base {
     let typeId = this.post('typeId');
     let valueId = this.post('valueId');
 
-    let collect = await this.model('collect').where({type_id: typeId, value_id: valueId, user_id: 1}).find();
+    let collect = await this.model('collect').where({type_id: typeId, value_id: valueId, user_id: think.userId}).find();
     let collectRes = null;
     let handleType = 'add';
     if (think.isEmpty(collect)) {
@@ -42,7 +49,7 @@ export default class extends Base {
         collectRes = await this.model('collect').add({
             type_id: typeId,
             value_id: valueId,
-            user_id: 1,
+            user_id: think.userId,
             add_time: parseInt(new Date().getTime() / 1000)
         });
     } else {

+ 2 - 2
src/api/controller/goods.js

@@ -68,7 +68,7 @@ export default class extends Base {
 
 
     //当前用户是否收藏
-    let userHasCollect = await this.model('collect').isUserHasCollect(1, 0, goodsId);
+    let userHasCollect = await this.model('collect').isUserHasCollect(think.userId, 0, goodsId);
 
     //记录用户的足迹 TODO
     await await this.model('footprint').addFootprint(goodsId);
@@ -140,7 +140,7 @@ export default class extends Base {
       //添加到搜索历史
       let keywords = await this.model('search_history').add({
         keyword: keyword,
-        user_id: 1,
+        user_id: think.userId,
         add_time: parseInt(new Date().getTime() / 1000)
       });
 

+ 4 - 4
src/api/controller/order.js

@@ -21,7 +21,7 @@ export default class extends Base {
      */
     async listAction() {
 
-        let orderList = await this.model('order').where({user_id: 1}).page(1, 10).countSelect();
+        let orderList = await this.model('order').where({user_id: think.userId}).page(1, 10).countSelect();
 
         let newOrderList = [];
         for (let item of orderList.data) {
@@ -50,7 +50,7 @@ export default class extends Base {
 
     async detailAction() {
         let orderId = this.get('orderId');
-        let orderInfo = await this.model('order').where({user_id: 1, id: orderId}).find();
+        let orderInfo = await this.model('order').where({user_id: think.userId, id: orderId}).find();
 
         if (think.isEmpty(orderInfo)) {
             return this.fail('订单不存在');
@@ -102,7 +102,7 @@ export default class extends Base {
         let freightPrice = 0.00;
 
         //获取要购买的商品
-        let checkedGoodsList = await this.model('cart').where({user_id: 1, session_id: 1, checked: 1}).select();
+        let checkedGoodsList = await this.model('cart').where({user_id: think.userId, session_id: 1, checked: 1}).select();
         if (think.isEmpty(checkedGoodsList)) {
             return this.fail('请选择商品');
         }
@@ -130,7 +130,7 @@ export default class extends Base {
         let orderInfo = {
 
             order_sn: this.model('order').generateOrderNumber(),
-            user_id: 1,
+            user_id: think.userId,
 
             //收货地址和运费
             consignee: checkedAddress.name,

+ 2 - 2
src/api/controller/search.js

@@ -13,7 +13,7 @@ export default class extends Base {
     //取出热闹关键词
     let hotKeywordList = await this.model('keywords').distinct('keyword').field(['keyword', 'is_hot']).limit(10).select();
 
-    let historyKeywordList = await this.model('search_history').distinct('keyword').where({ user_id: 1 }).limit(10).getField('keyword');
+    let historyKeywordList = await this.model('search_history').distinct('keyword').where({ user_id: think.userId }).limit(10).getField('keyword');
 
     return this.success({
       defaultKeyword: defaultKeyword,
@@ -30,7 +30,7 @@ export default class extends Base {
   }
 
   async clearhistoryAction() {
-    let historyKeywordList = await this.model('search_history').where({ user_id: 1 }).delete();
+    let historyKeywordList = await this.model('search_history').where({ user_id: think.userId }).delete();
     return this.success();
   }
 }

+ 75 - 0
src/api/service/token.js

@@ -0,0 +1,75 @@
+'use strict';
+
+const jwt = require('jsonwebtoken');
+
+const secret = think.config('session.secret');
+
+export default class extends think.service.base {
+  /**
+   * init
+   * @return {}         []
+   */
+  init(...args) {
+    super.init(...args);
+  }
+
+  /**
+   * 根据header中的X-Nideshop-Token值获取用户id
+   */
+  async getUserId() {
+
+    const token = think.token;
+
+    if (!token) {
+      return 0;
+    }
+
+    let result = await this.parse();
+
+    if (think.isEmpty(result) || result.user_id <= 0) {
+      return 0;
+    }
+
+    return result.user_id;
+  }
+
+  /**
+   * 根据值获取用户信息
+   */
+  async getUserInfo() {
+
+    let userId = await this.getUserId();
+    if (userId <= 0) {
+      return null;
+    }
+
+    let userInfo = await this.model('user').field(['id', 'username', 'nickname', 'gender', 'avatar', 'birthday']).where({ id: userId }).find();
+
+    return think.isEmpty(userInfo) ? null : userInfo;
+  }
+
+  async create(userInfo) {
+    let token = jwt.sign(userInfo, secret);
+    return token;
+  }
+
+  async parse() {
+    if (think.token) {
+      try {
+        return jwt.verify(think.token, secret);
+      } catch (err) {
+        return null;
+      }
+    }
+    return null;
+  }
+
+  async verify() {
+    let result = await this.parse();
+    if (think.isEmpty(result)) {
+      return false;
+    }
+
+    return true;
+  }
+}

+ 1 - 1
src/common/bootstrap/global.js

@@ -22,5 +22,5 @@ global.getTime = function () {
 };
 
 global.getLoginUserId = function () {
-  return 1;
+  return think.userId 
 };

+ 5 - 5
src/common/config/config.js

@@ -3,13 +3,13 @@
  * config
  */
 export default {
-  //key: value
-  default_module: 'api', //设置默认模块
-  deny_module_list: [], //设置禁用的模块
+    //key: value
+    default_module: 'api', //设置默认模块
+    deny_module_list: [], //设置禁用的模块
 
-    cors:{
+    cors: {
         origin: '*',
         methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
         preflightContinue: false
-    }
+    },
 };

+ 1 - 1
src/common/config/session.js

@@ -7,7 +7,7 @@ export default {
   name: 'thinkjs',
   type: 'file',
   secret: 'T^%*$XC@',
-  timeout: 24 * 3600,
+  timeout: 30 * 24 * 3600,
   cookie: { // cookie options
     length: 32,
     httponly: true

+ 3 - 3
src/common/model/cart.js

@@ -9,7 +9,7 @@ export default class extends think.model.base {
    * @returns {Promise.<*>}
    */
   async getGoodsList(){
-    return await this.model('cart').where({user_id: 1, session_id: 1}).select();
+    return await this.model('cart').where({user_id: think.userId, session_id: 1}).select();
   }
 
   /**
@@ -17,7 +17,7 @@ export default class extends think.model.base {
    * @returns {Promise.<*>}
    */
   async getCheckedGoodsList(){
-    return await this.model('cart').where({user_id: 1, session_id: 1, checked: 1}).select();
+    return await this.model('cart').where({user_id: think.userId, session_id: 1, checked: 1}).select();
   }
 
     /**
@@ -25,6 +25,6 @@ export default class extends think.model.base {
      * @returns {Promise.<*>}
      */
   async clearBuyGoods(){
-      return await this.model('cart').where({user_id: 1, session_id: 1, checked: 1}).delete();
+      return await this.model('cart').where({user_id: think.userId, session_id: 1, checked: 1}).delete();
   }
 }