寫系列文章最容易出現的狀況是寫到一半,而後寫不下去了。一個因素是人變懶了;一個因素是這幾天在整理用戶模塊這部分的知識,發現有太多的內容要寫,而深刻Google以後又發現好多內容是本身未知的,寫着寫着就不知道該如何寫了。linux
常見的和用戶模塊相關的操做有:註冊登陸、信息修改、退出登陸ios
一個系統中,用戶模塊是最基礎也是最重要的。若是隻考慮一種登陸方式,那用戶表能夠用一張
users
表搞定一切。可是現實狀況是登陸方式有不少種,好比:帳號密碼登陸
,微信、QQ、微博登陸
,手機號、郵箱登陸
。並且一個用戶能夠使用帳號密碼登陸
以後再關聯微信、QQ、微博
,以後能夠直接使用微信、QQ、微博
登陸;那麼如何保證設計用戶表
將變得相當重要。數據庫
參考:axios
經過以上部分博文的介紹,咱們能夠將用戶表設計爲:用戶基礎表:user_base
,用戶受權表:user_auth
,用戶擴展表:user_extends
。小程序
用戶基礎表:uid、user_role、user_name、avatar、password、signature、birthday、gender等segmentfault
用戶受權表:id、uid、identity_type、identifier、certificate等微信小程序
用戶擴展表:id、uid、device_name、device_id、vendor、client_name、client_version等api
以上的用戶表的設計能夠參考: 用戶系統設計與實現服務器
ps:我這個項目的用戶表設計當時沒有考慮那麼多,只考慮了
微信小程序端
的設計,先給本身留個坑之後再將項目完善吧。先介紹目前的實現方式。微信
我目前的實現步驟以下:
在app/models
包下建立user.js
:用戶表的相關字段以及用戶表的操做
User.init({ id: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true }, nickname: Sequelize.STRING, email: { type: Sequelize.STRING(128), // 添加惟一(unique)約束後插入重複值會報錯 unique: true }, password: { type: Sequelize.STRING, set(val) { // 使用 bcryptjs 庫對密碼加密處理 const salt = bcrypt.genSaltSync(10) const psw = bcrypt.hashSync(val, salt) // 設置 password 的值 this.setDataValue('password', psw) } }, openid: { type: Sequelize.STRING(64), unique: true }, gender: Sequelize.INTEGER, balance: Sequelize.INTEGER, avatar_url: Sequelize.STRING, city: Sequelize.STRING, country: Sequelize.STRING, province: Sequelize.STRING }, { sequelize, tableName: 'users' }) module.exports = { User }
微信小程序端不須要註冊,直接使用微信受權登陸便可。
這裏的註冊是指用戶在Web、App 端
使用郵箱、用戶名、密碼完成註冊。
在app/api/v1
包下建立user.js
:
/** * 用戶名密碼註冊 */ router.post('/register', async (ctx) => { const v = await new RegisterValidator().validate(ctx) // 令牌獲取 頒佈令牌 const user = { email: v.get('body.email'), password: v.get('body.password2'), nickname: v.get('body.nickname') } // 使用 Sequlize 保存到數據庫 await User.create(user) success() }) module.exports = router
調用:
http://192.168.*.***:3000/v1/user/register
,在表單中填寫郵箱、用戶名、密碼,而後將結果傳遞給api
便可
使用帳號(郵箱)密碼登陸
/** * 郵箱登陸:用戶不存在會提示帳戶不存在,用戶存在則驗證用戶信息,登陸成功以後返回 token * @param {帳號} account * @param {密碼} secret */ async function emailLogin(account, secret) { const user = await User.verifyEmailPassword(account, secret) return token = generateToken(user.id, Auth.USER) }
微信小程序使用token
登陸
在app/service
包下建立wx.js
:獲取登陸的token
class WXManager { /** * 小程序登陸 * @param {小程序中傳遞的 code} code * @param {小程序中公開的用戶信息} userInfo */ static async codeToToken(code, userInfo) { const url = util.format(global.config.wx.loginUrl, global.config.wx.appId, global.config.wx.appSecret, code) // 調用微信提供的接口 const result = await axios.get(url) if (result.status !== 200) { throw new global.errs.AuthFailed('openid獲取失敗') } // 微信中最終判斷是經過 errcode 判斷 const errcode = result.data.errcode const errmsg = result.data.errmsg if (errcode){ throw new global.errs.AuthFailed('openid獲取失敗:'+errmsg) } // openid // 檔案 user uid openid 長 // openid // 用戶是否存在,例如 token 過時的狀況 let user = await User.getUserByOpenid(result.data.openid) if(!user){ user = await User.registerByOpenid(result.data.openid, userInfo) } return generateToken(user.id, Auth.USER) } } module.exports = { WXManager }
(1)帳號密碼登陸調用:
http://192.168.*.***:3000/v1/token
,在表單中填寫郵箱、密碼,而後將結果傳遞給api
便可;(2)小程序登陸調用:先進行小程序登陸,而後調用http://192.168.*.***:3000/v1/token
,將小程序提供的code
發送給api
便可
無論是帳號密碼登陸
仍是微信小程序登陸
,都返回了token
主要是用於API 鑑權、登陸狀態保持
在core
包下建立util.js
:生成token
的工具類
/** * 使用 JWT 生成 token * @param {用戶 id} uid * @param {用戶權限} scope */ const generateToken = function (uid, scope) { const secretKey = global.config.security.secretKey const expiresIn = global.config.security.expiresIn // 在 token 中寫入 uid、scope 數據 const token = jwt.sign({ uid, scope }, secretKey, { expiresIn: expiresIn }) return token } module.exports = { generateToken, }
關於
JWT
的介紹能夠查看我以前寫的文章:全棧項目|小書架|服務器開發-JWT 詳解,或者這篇文章:JWT 超詳細分析
用戶信息的修改須要調用
update
信息便可,若是是修改密碼
還須要將本地的登陸狀態
清除,從新登陸。
具體的修改信息,後續接口實現了再補上。
這篇文章介紹的不錯:How to log out when using JWT
文中描述的主要方式有下面幾種:
token
token
維護黑名單的方式有人認爲會致使黑名單列表過長,這裏能夠經過判斷token
是否過時,過時則自動刪除。
本項目只是從客戶端刪除token
的方式實現退出登陸。
其餘的處理方式參考:
諮詢請加微信:輕撩便可。