寫系列文章最容易出現的狀況是寫到一半,而後寫不下去了。一個因素是人變懶了;一個因素是這幾天在整理用戶模塊這部分的知識,發現有太多的內容要寫,而深刻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
以上的用戶表的設計能夠參考: 用戶系統設計與實現bash
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
的方式實現退出登陸。
其餘的處理方式參考:
諮詢請加微信:輕撩便可。
![]()