記一次業餘專案的敏捷開發實踐
阿新 • • 發佈:2020-03-15
本次是在原有ApiTemplate專案之上,增加一個使用者登入許可權控制模組,用於驗證ApiTemplate專案在面對一些簡單問題時,如何抽象並支援未來的擴充套件。使用者登入許可權控制模組看上去很簡單,但由於業餘時間總是有限的。所以藉助此機會實踐一次使用者敏捷開發。首先拆分模組,本次只實現使用者登入和登出。
apitemplate專案地址:https://github.com/cqhaibin/ApiTemplate
一、總結放前面
最小化任務範圍
- 本次任務只限定在了《使用者名稱+密碼登入》這個任務上,並且不包含資料的持久化, 這樣在做的時候反覆考查自己,不讓自己超出範圍。所以
- 查詢使用者註冊資訊、線上使用者儲存相關介面只做定義和模擬實現,不做具體的儲存實現
- 考慮到業務邏輯是穩定的,而儲存是可變的,所以資料庫實體物件與業務實體物件分離
給任務一個期限
像本次就只列出了任務的期限,而沒有列出每個子階段的期限,如:一個需求必須要經過需求分析、模組設計、程式碼實現等階段。這些子階段也需要給出具體的期限。
從外向裡逐層推進
- 定義UI/服務層介面
因為UI介面有多種提供方式(如:rest api, rpc等),所以基本以服務層介面為標準,UI介面層只是做了一次簡單轉換和呼叫。其中UI/服務層介面輸入/輸出引數的Moddel也隨之定義(兩層共享Model) - 實現服務層介面
此步實現服務層介面,你會發現還需要依賴線上使用者管理模組,以及資料庫層(查詢註冊使用者資訊),在這裡我只定義了查詢註冊使用者資訊的介面,而暫不做具體的實現。然後進入第三步 - 定義線上使用者模組的介面
此步包含:線上使用者管理實體介面、線上使用者實體介面。定義好後先不實現。完善服務層實現中對此模組的依賴呼叫,在這裡你可能會反覆調整線上使用者模組的方法輸入/輸出引數的Model,以達到與服務層的融合 - 實現線上使用者模組的介面
此步實現 線上使用者管理實體介面、線上使用者實體介面。此時我們發現還要依賴線上使用者儲存介面(只定義,不做實現)
二、使用者需求
實現根據使用者名稱的登入、登出介面。
三、需求分析
- 使用者名稱:支援英文、數字、漢字、以及特殊字元;使用者名稱不區分大小寫
- 密碼:支援英文、數字、特殊字元,區分大小寫
- 提示:使用者不存在與密碼錯誤要區分提示
- 此階段不考慮資料持久化,因為要快速驗證原型的可行性
四、系統設計
介面設計
介面統一使用rest api, 實現登入、登出兩個介面
- 登入介面
- 介面名:PostLogin
- 請求型別:post
- 輸入引數
{ userName<string>, //使用者名稱 password<string> //密碼 }
- 返回引數
{ isSuccess<bool>, //請求是否成功 resultCode<number>, //請求狀態Code 200006:賬號不存在;200001:賬號被禁用;200002:密碼錯誤 data<object>:{ token<string> //登入成功後,返回的token user<object>:{ //使用者物件 realName<string>, //使用者名稱 userName<string>, //登入名 id<int>, //使用者Id config<string>, //使用者擴充套件資訊,json字串 mobilePhone<string>, //電話號碼 } } }
- 登出介面
- 介面名稱:LoginOut
- 請求型別:get
- 輸入引數
通過url, header, cookie的順序獲取token - 返回引數
{ isSuccess<bool>, //請求是否成功 resultCode<number>, //請求狀態Code }
詳細設計
登入介面詳細設計
- 流程
- 線上使用者管理
- 線上使用者管理介面類
class IOnlineUserMgr{ /// <summary> /// 將使用者新增到線上使用者列表,此方法需要對登入資訊持久化 /// </summary> /// <param name="entity"></param> void Add(IUserEntity entity); /// <summary> /// 根據token移除對應的使用者,此方法需要對登出資訊持久化 /// </summary> /// <param name="token"></param> /// <returns></returns> bool Remove(string token); /// <summary> /// 根據使用者Id移除使用者,此方法需要對登出資訊持久化 /// </summary> /// <param name="id"></param> /// <returns></returns> bool Remove(int id); /// <summary> /// 從持久化層恢復線上使用者 /// </summary> void Load(); /// <summary> /// 獲取所有線上使用者 /// </summary> IList<IUserEntity> GetAll(); IUserEntity Get(int userId); }
- 使用者實體介面類
class IUserEntity{ UserInfo UserInfo { get; } string Token { get; } /// <summary> /// 客戶端資訊 /// </summary> RequestClientInfo ClientInfo { get; } DateTime LoginTime { get; } DateTime ExpiredTime { get; } /// <summary> /// 使用者登入配置 /// </summary> UserAuthOption Option { get; } TokenEntity GetTokenEntity(); }
- 說明
- token生成規則
使用者key = token_UserId_UserName_IP_OS_Time,然後將使用者key通過MD5計算出的值作為token - UAParser
實現UserAgent字串到物件的轉換。
- token生成規則
登出介面詳細設計
- 流程
五、資料字典
- 線上使用者資訊
- 使用者