記一次業餘項目的敏捷開發實踐
- 2020 年 3 月 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生成規則
登出接口詳細設計
- 流程
五、數據字典
- 在線用戶信息
- 用戶