composer-rest-server認證實現(xiàn)
在composer里面關(guān)于用戶有兩種模式。
- 多用戶模式,用戶為參與者。和composer-rest-server并無太大關(guān)系,僅作為智能合約里面的參與者。用戶通過認證,可以獨立執(zhí)行composer-rest-server,以實現(xiàn)權(quán)限隔離。
- 認證模式。多個用戶(不是參與者)訪問同一個restful接口,需要做一定的認證操作,避免對區(qū)塊鏈的過度訪問。這種模式實在compsoser-rest-server層面發(fā)生的,認證過程不會和區(qū)塊鏈有任何互動。
這篇文章所講的就是第二種方式。
composer-rest-server是通過loopback構(gòu)建的一個項目,所以權(quán)限管理大致和loopback相同。
這里提供兩種方式供選擇
-
直接使用loopback用戶認證(推薦)
loopback提供了簡單的用戶模塊,在composer的實現(xiàn)中,用戶被隱藏起來了,所以只需要開放登錄、登出接口即可。需要解決的問題:
- composer實現(xiàn)只是在內(nèi)存保存了數(shù)據(jù)。如果需要管理用戶,需要使用數(shù)據(jù)庫
- 開放user數(shù)據(jù)模塊之后,開放的接口太多,需要隱藏一部分
解決方式
- 修改 /server/datasources.json 為
{ "db": { "name": "db", "connector": "memory" }, //添加mysql依賴。注意:使用mysql需要在package.json添加 "loopback-connector-mysql":"5.2.0" 依賴 "mysqlDs": { "name": "mysqlDs", "connector": "mysql", "host": "localhost", "port": 3306, "database": "db_rest_server", //需新建數(shù)據(jù)庫和user表。 "username": "root", "password": "123456" } }
- 修改 /server/model-config.json
... "user": { "dataSource": "mysqlDs", //修改數(shù)據(jù)源 memory 為 mysql "public": true //開發(fā) }, ...
- 新增腳本 /server/root/create-models.js
loopback里面,server/boot 下面的腳本會在程序啟動的時候執(zhí)行
'use strict'; module.exports = function(app) { //FIXME only run this script AT first TIME . For create table. // app.dataSources.mysqlDs.automigrate('user', function(err) { // if (err) throw err; // // app.models.user.create([{ // username: 'test1', // email:'test1@email.com', // password: 'test1', // }], function(err, coffeeShops) { // if (err) throw err; // console.log('Models created: \n', coffeeShops); // }); // }); app.models.user.disableRemoteMethodByName("upsert"); // disables PATCH /app.models.users app.models.user.disableRemoteMethodByName("find"); // disables GET /app.models.users app.models.user.disableRemoteMethodByName("replaceOrCreate"); // disables PUT /app.models.users app.models.user.disableRemoteMethodByName("create"); // disables POST /app.models.users app.models.user.disableRemoteMethodByName("prototype.updateAttributes"); // disables PATCH /app.models.users/{id} app.models.user.disableRemoteMethodByName("findById"); // disables GET /app.models.users/{id} app.models.user.disableRemoteMethodByName("exists"); // disables HEAD /app.models.users/{id} app.models.user.disableRemoteMethodByName("replaceById"); // disables PUT /app.models.users/{id} app.models.user.disableRemoteMethodByName("deleteById"); // disables DELETE /app.models.users/{id} app.models.user.disableRemoteMethodByName('prototype.__get__accessTokens'); // disable GET /app.models.users/{id}/accessTokens app.models.user.disableRemoteMethodByName('prototype.__create__accessTokens'); // disable POST /app.models.users/{id}/accessTokens app.models.user.disableRemoteMethodByName('prototype.__delete__accessTokens'); // disable DELETE /app.models.users/{id}/accessTokens app.models.user.disableRemoteMethodByName('prototype.__get__credentials'); // disable GET /app.models.users/{id}/accessTokens app.models.user.disableRemoteMethodByName('prototype.__create__credentials'); // disable POST /app.models.users/{id}/accessTokens app.models.user.disableRemoteMethodByName('prototype.__delete__credentials'); // disable DELETE /app.models.users/{id}/accessTokens app.models.user.disableRemoteMethodByName('prototype.__get__identities'); // disable GET /app.models.users/{id}/accessTokens app.models.user.disableRemoteMethodByName('prototype.__create__identities'); // disable POST /app.models.users/{id}/accessTokens app.models.user.disableRemoteMethodByName('prototype.__delete__identities'); // disable DELETE /app.models.users/{id}/accessTokens app.models.user.disableRemoteMethodByName('prototype.__findById__accessTokens'); // disable GET /app.models.users/{id}/accessTokens/{fk} app.models.user.disableRemoteMethodByName('prototype.__updateById__accessTokens'); // disable PUT /app.models.users/{id}/accessTokens/{fk} app.models.user.disableRemoteMethodByName('prototype.__destroyById__accessTokens');// disable DELETE /app.models.users/{id}/accessTokens/{fk} app.models.user.disableRemoteMethodByName('prototype.__findById__identities'); // disable GET /app.models.users/{id}/accessTokens/{fk} app.models.user.disableRemoteMethodByName('prototype.__updateById__identities'); // disable PUT /app.models.users/{id}/accessTokens/{fk} app.models.user.disableRemoteMethodByName('prototype.__destroyById__identities');// disable DELETE /app.models.users/{id}/accessTokens/{fk} app.models.user.disableRemoteMethodByName('prototype.__findById__credentials'); // disable GET /app.models.users/{id}/accessTokens/{fk} app.models.user.disableRemoteMethodByName('prototype.__updateById__credentials'); // disable PUT /app.models.users/{id}/accessTokens/{fk} app.models.user.disableRemoteMethodByName('prototype.__destroyById__credentials');// disable DELETE /app.models.users/{id}/accessTokens/{fk} app.models.user.disableRemoteMethodByName('prototype.__count__accessTokens'); // disable GET /app.models.users/{id}/accessTokens/count app.models.user.disableRemoteMethodByName('prototype.__count__credentials'); // disable GET /app.models.users/{id}/accessTokens/count app.models.user.disableRemoteMethodByName('prototype.__count__identities'); // disable GET /app.models.users/{id}/accessTokens/count app.models.user.disableRemoteMethodByName("prototype.verify"); // disable POST /app.models.users/{id}/verify app.models.user.disableRemoteMethodByName("changePassword"); // disable POST /app.models.users/change-password app.models.user.disableRemoteMethodByName("createChangeStream"); // disable GET and POST /app.models.users/change-stream app.models.user.disableRemoteMethodByName("confirm"); // disables GET /app.models.users/confirm app.models.user.disableRemoteMethodByName("count"); // disables GET /app.models.users/count app.models.user.disableRemoteMethodByName("findOne"); // disables GET /app.models.users/findOne //app.models.user.disableRemoteMethodByName("login"); // disables POST /app.models.users/login //app.models.user.disableRemoteMethodByName("logout"); // disables POST /app.models.users/logout app.models.user.disableRemoteMethodByName("resetPassword"); // disables POST /app.models.users/reset app.models.user.disableRemoteMethodByName("setPassword"); // disables POST /app.models.users/reset-password app.models.user.disableRemoteMethodByName("update"); // disables POST /app.models.users/update app.models.user.disableRemoteMethodByName("upsertWithWhere"); // disables POST /app.models.users/upsertWithWhere };
- composer-rest-server-local -c cardName -a true [-n never] 啟動服務(wù)
在user表新建一條數(shù)據(jù)。使用 /user/login ,即可獲取accessToken。在之后的請求里面,添加請求頭:X-Access-Token: 對應(yīng)token ,即可獲取認證通過。
-
passport實現(xiàn)認證
passport是一個用來專門管理用戶登錄的一個庫。包含n多第三方登錄,已經(jīng)local登錄。適用于任何express擴展出來的項目。
但是這個的針對auth、auth2等做的個庫,所以如果是想提供直接提供api以獲得token有些麻煩。
使用方式:
修改 /server/providers.json
{ "local": { //名稱 "provider": "local", "module": "passport-local", //這里表示使用本地用戶。還有:github、google等授權(quán)庫 "usernameField": "username", //必須字段 "passwordField": "password", "authPath": "/auth/local", //認證跳轉(zhuǎn)地址 "successRedirect": "/", //成功回調(diào) "failureRedirect": "/" //失敗回調(diào) } }
直接訪問設(shè)置的認證地址,在回調(diào)地址里面的session就能獲取到accessToken。
遇到的問題:
本來是計劃直接接入passport-local,不暴露user模塊的,但是發(fā)現(xiàn)獲取token方式太復(fù)雜,涉及到重定向,針對調(diào)用不友好,所以放棄了。為了避免修改loopback-componet-passport包內(nèi)容,所以建議直接使用方式1.